How to change nvbuffer to cpu-buffer when nvarguscamerasrc is working in bufapi-version mode?

The pipeline structure : nvarguscamesrc(cap:NVMM/NV12,25fps,4000*3000)->nvvidconvert->appsink.
I got the nvmm-buffer in the appsink’s “new-sample”-callback,then I can change nvbuffer to cpu-buffer when nvarguscamerasrc was working without bufapi-version by using the following API:

Now I want to add nvinfer to the pipeline,so the nvarguscamesrc need to set “bufapi-version” from false to true,
but over this operated, the map.size was change to 64 and the api -“ExtractFdFromNvBuffer” return error.

How to change nvbuffer to cpu-buffer when nvarguscamerasrc is working in bufapi-version mode?

Hi,
For setting bufapi-version=true, please use NvBufSurface APIs. You may refer to

/opt/nvidia/deepstream/deepstream-6.0/sources/gst-plugins/gst-dsexample/gstdsexample.cpp

The demo code is in get_converted_mat(). Please also check APIs in

/opt/nvidia/deepstream/deepstream-6.0/sources/includes/nvbufsurface.h
/opt/nvidia/deepstream/deepstream-6.0/sources/includes/nvbufsurftransform.h

Hello,DaneLLL
I had got Segmentation fault when dealing with a copy of a nvmemory map,whether NV12 data requires additional operations?
The test code is shown below(Segmentation falut position :memcpy((char*)snap_yuv_img.data,dst_surface->surfaceList[0].mappedAddr.addr[0],400030003/2);):

GstBuffer *gstbuffer = gst_sample_get_buffer(sample);
if(gstbuffer)
{
GstMapInfo map;
if (gst_buffer_map(gstbuffer, &map, GST_MAP_READ))
{
if(0 < need_snap_counter && 0 == is_snap_process && 0 == storage_spacefull_flag)
{
NvBufSurface *surface = NULL;
NvBufSurfTransformRect src_rect, dst_rect;
surface = (NvBufSurface *) map.data;
int batch_size= surface->batchSize;
src_rect.top = 0;
src_rect.left = 0;
src_rect.width = (guint) surface->surfaceList[0].width;
src_rect.height= (guint) surface->surfaceList[0].height;
dst_rect.top = 0;
dst_rect.left = 0;
dst_rect.width = 4000;
dst_rect.height= 3000;

		NvBufSurfTransformParams nvbufsurface_params;
		nvbufsurface_params.src_rect = &src_rect;
		nvbufsurface_params.dst_rect = &dst_rect;
		nvbufsurface_params.transform_flag = NVBUFSURF_TRANSFORM_NORMALIZE; //NVBUFSURF_TRANSFORM_CROP_SRC | NVBUFSURF_TRANSFORM_CROP_DST;
		nvbufsurface_params.transform_filter = NvBufSurfTransformInter_Default;

		NvBufSurface *dst_surface = NULL;
		NvBufSurfaceCreateParams nvbufsurface_create_params;

		nvbufsurface_create_params.gpuId  = surface->gpuId;
		nvbufsurface_create_params.width  = (gint) surface->surfaceList[0].width;
		nvbufsurface_create_params.height = (gint) surface->surfaceList[0].height;
		nvbufsurface_create_params.size = 0;
		nvbufsurface_create_params.colorFormat = NVBUF_COLOR_FORMAT_NV12;
		nvbufsurface_create_params.layout = NVBUF_LAYOUT_PITCH;
		nvbufsurface_create_params.memType = NVBUF_MEM_DEFAULT;
		
		cudaSetDevice (surface->gpuId);
		cudaStream_t cuda_stream;
		cudaStreamCreate (&cuda_stream);
		int create_result = NvBufSurfaceCreate(&dst_surface,batch_size,&nvbufsurface_create_params);
		
		NvBufSurfTransformConfigParams transform_config_params;
		NvBufSurfTransform_Error err;
		
		transform_config_params.compute_mode = NvBufSurfTransformCompute_Default;
		transform_config_params.gpu_id = surface->gpuId;
		err = NvBufSurfTransformSetSessionParams (&transform_config_params);
		
		NvBufSurfaceMemSet (dst_surface, 0, 0, 0);
		err = NvBufSurfTransform (surface, dst_surface, &nvbufsurface_params);
		if (err != NvBufSurfTransformError_Success) 
		{
		   g_print ("Error: NvBufSurfTransform failed with error %d while converting buffer\n", err);
		}

		NvBufSurfaceMap (dst_surface, 0, 0, NVBUF_MAP_READ);
		NvBufSurfaceSyncForCpu (dst_surface, 0, 0);
		printf("over NvBufSurfaceSyncForCpu!\r\n");

		need_snap_counter--;
		char currentfolder[64] = {0};
		//nv_dump_dmabuf_to_cpu_memory(dmabuf_fd,0,&templen,(char*)snap_yuv_img.data);
		//nv_dump_dmabuf_to_cpu_memory(dmabuf_fd,1,&templen,(char*)snap_yuv_img.data);    
		memcpy((char*)snap_yuv_img.data,dst_surface->surfaceList[0].mappedAddr.addr[0],4000*3000*3/2);

		printf("over memocpy!\r\n");
		memset(&pub_jpeg_header,0,sizeof(pub_jpeg_header));                    
		get_snap_timestr(currentfolder);
		make_exifparam(&pub_jpeg_header, currentfolder, snap_savepath, index);                       
		is_snap_process = 1;
		if (NvBufSurfaceUnMap (dst_surface, 0, 0))
		{
			printf("Error:NvBufSurfaceUnMap fail!\r\n");
		}
		
		if (NvBufSurfaceDestroy (dst_surface))
		{
			printf("Error:NvBufSurfaceDestroy fail\r\n");
		}
	 }
}
gst_buffer_unmap(gstbuffer, &map);

}

Hi,
Frame data in NV12 has two surfaces. One is Y plane with 4000x3000 bytes. The other is UV plane with 4000x3000x0.5 bytes. Looks like you only map oone surface instead of two.

Hello,DaneLLL
I had modify the demo to test two sufaces,but there was wrong with it’s width and it’s height,do you have examples of NV12 conversions?


image

Hi,
Please call

NvBufSurfaceMap (dst_surface, 0, 1, NVBUF_MAP_READ);

and read data from dst_surface->surfaceList[0].mappedAddr.addr[1].

There are patches about creating buffer and call NvBufSurfaceTransform(). Please take a look at
How to include opencv to deepstream-test5-app - #14 by DaneLLL
How to crop the image and save - #2 by DaneLLL
RTSP camera access frame issue - #19 by DaneLLL
Uridecodebin with filesink - #13 by DaneLLL

1 Like

Thank you for your help,I solved the problem your way.
Are these processes thread safe?I want to use them in multiple threads.

Hi,
If you will access one buffer in multiple threads, may try to call NvBufSurfTransformAsync() and NvBufSurfTransformSyncObjWait(). So that performance is better. NvBufSurfTransform() is a block operation and may slow other threads.

1 Like