RTSP camera access frame issue

Hi,
Not sure. Probably the memory is not released and after some time it is not able to allocate new memory.

Hi DaneLLL,

How to implement the logic for multiple camera streams. I suppose the solution is for single camera streams. For instance, if there are two camera streams with same input resolution then what changes might need to be done to the code above? From my understanding, the following change will suffice. Please correct if I am wrong.

surface->surfaceList[0] ----> surface->surfaceList[1]

Thanks.

Hi,
Here is an example of running two rtsp sources.
For two sources, batch-size has to be set to two and surfaceList[0] is source0, surfaceList[1] is source1.

Hi DaneLLL,

I tried your suggestion. I also referred the documentation for providing appropriate parameters. I could understand that I need to pass -1 for computation of all buffers. However, I am still unable to get the output for second stream. I get null pointer for “dst_surface->surfaceList[1].mappedAddr.addr[0]” using these parameters. Please find my code below:

/**
 * Buffer probe function after tracker.
 */
static GstPadProbeReturn
tracking_done_buf_prob (GstPad * pad, GstPadProbeInfo * info, gpointer u_data)
{
	NvDsInstanceBin *bin = (NvDsInstanceBin *) u_data;
	guint index = bin->index;
	AppCtx *appCtx = bin->appCtx;
	GstBuffer *buf = (GstBuffer *) info->data;
	std::vector<std::string> frame_data;
	GstClockTime timestamp = buf->pts;

	NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);
	if (!batch_meta) {
	NVGSTDS_WARN_MSG_V ("Batch meta not found for buffer %p", buf);
	return GST_PAD_PROBE_OK;
	}

	curr_timepoint = std::chrono::high_resolution_clock::now();
	std::chrono::duration<double> time_span = 
					std::chrono::duration_cast<std::chrono::duration<double>>
					(curr_timepoint - prev_timepoint);	

	if(time_span.count() > time_interval_secs)
	{
		#if 1
		GstMapInfo in_map_info;
		NvBufSurface *surface = NULL;

		memset (&in_map_info, 0, sizeof (in_map_info));
		if (!gst_buffer_map (buf, &in_map_info, GST_MAP_READ)) {
		g_print ("Error: Failed to map gst buffer\n");
		gst_buffer_unmap (buf, &in_map_info);
		return GST_PAD_PROBE_OK;
		}

		cudaError_t cuda_err;

		NvBufSurfTransformRect src_rect, dst_rect;
		surface = (NvBufSurface *) in_map_info.data;  

		int batch_size= surface->batchSize;
		printf("\nBatch Size : %d, resolution : %dx%d \n",batch_size,
		surface->surfaceList[0].width, surface->surfaceList[0].height);

		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 = (guint) surface->surfaceList[0].width;
		dst_rect.height= (guint) surface->surfaceList[0].height;

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

		NvBufSurface *dst_surface = NULL;
		NvBufSurfaceCreateParams nvbufsurface_create_params;

		/* An intermediate buffer for NV12/RGBA to BGR conversion  will be
		* required. Can be skipped if custom algorithm can work directly on NV12/RGBA. */
		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_RGBA;
		nvbufsurface_create_params.layout = NVBUF_LAYOUT_PITCH;
		nvbufsurface_create_params.memType = NVBUF_MEM_DEFAULT;

		cuda_err = cudaSetDevice (surface->gpuId);

		cudaStream_t cuda_stream;

		cuda_err=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;
		transform_config_params.cuda_stream = cuda_stream;
		err = NvBufSurfTransformSetSessionParams (&transform_config_params);

		//NvBufSurfaceMemSet (dst_surface, 0, 0, 0);
		NvBufSurfaceMemSet (dst_surface, -1, -1, 0);

		err = NvBufSurfTransform (surface, dst_surface, &nvbufsurface_params);
		if (err != NvBufSurfTransformError_Success) {
		g_print ("NvBufSurfTransform failed with error %d while converting buffer\n", err);
		}

		//NvBufSurfaceMap (dst_surface, 0, 0, NVBUF_MAP_READ);
		NvBufSurfaceMap (dst_surface, -1, -1, NVBUF_MAP_READ);

		//NvBufSurfaceSyncForCpu (dst_surface, 0, 0);
		NvBufSurfaceSyncForCpu (dst_surface, -1, -1);

		cv::Mat bgr_frame = cv::Mat (cv::Size(nvbufsurface_create_params.width,
					nvbufsurface_create_params.height), CV_8UC3);

		for(int cam_id = 0 ; cam_id < batch_size ; ++cam_id)
		{
			cv::Mat in_mat =
			cv::Mat (nvbufsurface_create_params.height, 
					nvbufsurface_create_params.width,
					CV_8UC4, dst_surface->surfaceList[cam_id].mappedAddr.addr[0],
					dst_surface->surfaceList[cam_id].pitch);

			cv::cvtColor (in_mat, bgr_frame, CV_RGBA2BGR);

			std::vector<uchar> encode_buffer;
			cv::imencode(".jpg",bgr_frame,encode_buffer);

			std::string encoded_jpeg;

			auto base64_jpeg = reinterpret_cast<const unsigned char*>
							(encode_buffer.data());
			encoded_jpeg = base64_encode(base64_jpeg, encode_buffer.size());
			frame_data.push_back(encoded_jpeg);		
		}

		NvBufSurfaceUnMap (dst_surface, 0, 0);
		NvBufSurfaceDestroy (dst_surface);
		cudaStreamDestroy (cuda_stream);
		gst_buffer_unmap (buf, &in_map_info);

		#endif

		/*
		* Output KITTI labels with tracking ID if configured to do so.
		*/
		write_kitti_track_output(appCtx, batch_meta);

	}

	if (appCtx->primary_bbox_generated_cb)
	appCtx->primary_bbox_generated_cb (appCtx, buf, batch_meta, index);
	return GST_PAD_PROBE_OK;
}

Kindly help me out.

Thanks.

Hi DaneLLL,

When I use the code below, I get the following error:

/**
 * Buffer probe function after tracker.
 */
static GstPadProbeReturn
tracking_done_buf_prob (GstPad * pad, GstPadProbeInfo * info, gpointer u_data)
{
	NvDsInstanceBin *bin = (NvDsInstanceBin *) u_data;
	guint index = bin->index;
	AppCtx *appCtx = bin->appCtx;
	GstBuffer *buf = (GstBuffer *) info->data;
	std::vector<std::string> frame_data;
	GstClockTime timestamp = buf->pts;

	NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);
	if (!batch_meta) {
	NVGSTDS_WARN_MSG_V ("Batch meta not found for buffer %p", buf);
	return GST_PAD_PROBE_OK;
	}

	curr_timepoint = std::chrono::high_resolution_clock::now();
	std::chrono::duration<double> time_span = 
					std::chrono::duration_cast<std::chrono::duration<double>>
					(curr_timepoint - prev_timepoint);	

	if(time_span.count() > time_interval_secs)
	{
		#if 1
		GstMapInfo in_map_info;
		NvBufSurface *surface = NULL;

		memset (&in_map_info, 0, sizeof (in_map_info));
		if (!gst_buffer_map (buf, &in_map_info, GST_MAP_READ)) {
		g_print ("Error: Failed to map gst buffer\n");
		gst_buffer_unmap (buf, &in_map_info);
		return GST_PAD_PROBE_OK;
		}

		cudaError_t cuda_err;

		NvBufSurfTransformRect src_rect, dst_rect;
		surface = (NvBufSurface *) in_map_info.data;  

		int batch_size= surface->batchSize;
		printf("\nBatch Size : %d, resolution : %dx%d \n",batch_size,
		surface->surfaceList[0].width, surface->surfaceList[0].height);

		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 = (guint) surface->surfaceList[0].width;
		dst_rect.height= (guint) surface->surfaceList[0].height;

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

		NvBufSurface *dst_surface = NULL;
		NvBufSurfaceCreateParams nvbufsurface_create_params;

		/* An intermediate buffer for NV12/RGBA to BGR conversion  will be
		* required. Can be skipped if custom algorithm can work directly on NV12/RGBA. */
		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_RGBA;
		nvbufsurface_create_params.layout = NVBUF_LAYOUT_PITCH;
		nvbufsurface_create_params.memType = NVBUF_MEM_DEFAULT;

		cuda_err = cudaSetDevice (surface->gpuId);

		cudaStream_t cuda_stream;

		cuda_err=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;
		transform_config_params.cuda_stream = cuda_stream;
		err = NvBufSurfTransformSetSessionParams (&transform_config_params);

		NvBufSurfaceMemSet (dst_surface, 0, 0, 0);
		NvBufSurfaceMemSet (dst_surface, 1, 0, 0);
		err = NvBufSurfTransform (surface, dst_surface, &nvbufsurface_params);

		if (err != NvBufSurfTransformError_Success) {
		g_print ("NvBufSurfTransform failed with error %d while converting buffer\n", err);
		}

		NvBufSurfaceMap (dst_surface, 0, 0, NVBUF_MAP_READ);
		NvBufSurfaceMap (dst_surface, 1, 0, NVBUF_MAP_READ);
		
		NvBufSurfaceSyncForCpu (dst_surface, 0, 0);
		NvBufSurfaceSyncForCpu (dst_surface, 1, 0);

		cv::Mat bgr_frame = cv::Mat (cv::Size(nvbufsurface_create_params.width,
					nvbufsurface_create_params.height), CV_8UC3);

		for(int cam_id = 0 ; cam_id < batch_size ; ++cam_id)
		{
			cv::Mat in_mat =
			cv::Mat (nvbufsurface_create_params.height, 
					nvbufsurface_create_params.width,
					CV_8UC4, dst_surface->surfaceList[cam_id].mappedAddr.addr[0],
					dst_surface->surfaceList[cam_id].pitch);

			cv::cvtColor (in_mat, bgr_frame, CV_RGBA2BGR);

			std::vector<uchar> encode_buffer;
			cv::imencode(".jpg",bgr_frame,encode_buffer);

			std::string encoded_jpeg;

			auto base64_jpeg = reinterpret_cast<const unsigned char*>
							(encode_buffer.data());
			encoded_jpeg = base64_encode(base64_jpeg, encode_buffer.size());
			frame_data.push_back(encoded_jpeg);		
		}

		NvBufSurfaceUnMap (dst_surface, 0, 0);
		NvBufSurfaceDestroy (dst_surface);
		cudaStreamDestroy (cuda_stream);
		gst_buffer_unmap (buf, &in_map_info);

		#endif

		/*
		* Output KITTI labels with tracking ID if configured to do so.
		*/
		write_kitti_track_output(appCtx, batch_meta);

	}

	if (appCtx->primary_bbox_generated_cb)
	appCtx->primary_bbox_generated_cb (appCtx, buf, batch_meta, index);
	return GST_PAD_PROBE_OK;
}

Error:

NvxBaseWorkerFunction[2575] comp OMX.Nvidia.std.iv_renderer.overlay.yuv420 Error -2147479552

Kindly help me out.

Thanks.

Hi,
For two sources and setting batch-size=2, You should see surface->surfaceList[0] and surface->surfaceList[1]. You have to create two destination surfaces like dst_surface and dst_surface1, copy surface->surfaceList[0] to dst_surface and surface->surfaceList[1] to dst_surface1.

Hi DaneLLL,

When I access surface->surfaceList[1] I get null pointer. Also the width and height are 0. Following is the code:

static GstPadProbeReturn
tracking_done_buf_prob (GstPad * pad, GstPadProbeInfo * info, gpointer u_data)
{
	NvDsInstanceBin *bin = (NvDsInstanceBin *) u_data;
	guint index = bin->index;
	AppCtx *appCtx = bin->appCtx;
	GstBuffer *buf = (GstBuffer *) info->data;
	std::vector<std::string> frame_data;
	GstClockTime timestamp = buf->pts;

	NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta (buf);
	if (!batch_meta) {
	NVGSTDS_WARN_MSG_V ("Batch meta not found for buffer %p", buf);
	return GST_PAD_PROBE_OK;
	}


		#if 1
		GstMapInfo in_map_info;
		NvBufSurface *surface = NULL;

		memset (&in_map_info, 0, sizeof (in_map_info));
		if (!gst_buffer_map (buf, &in_map_info, GST_MAP_READ)) {
		g_print ("Error: Failed to map gst buffer\n");
		gst_buffer_unmap (buf, &in_map_info);
		return GST_PAD_PROBE_OK;
		}

		cudaError_t cuda_err;

		NvBufSurfTransformRect src_rect, dst_rect;
		NvBufSurfTransformRect src_rect1, dst_rect1;

		surface = (NvBufSurface *) in_map_info.data;  

		int batch_size= surface->batchSize;
		printf("\nBatch Size : %d, resolution : %dx%d \n",batch_size,
		surface->surfaceList[1].width, surface->surfaceList[1].height);

		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 = (guint) surface->surfaceList[0].width;
		dst_rect.height= (guint) surface->surfaceList[0].height;

		src_rect1.top   = 0;
		src_rect1.left  = 0;
		src_rect1.width = (guint) surface->surfaceList[1].width;
		src_rect1.height= (guint) surface->surfaceList[1].height;

		dst_rect1.top   = 0;
		dst_rect1.left  = 0;
		dst_rect1.width = (guint) surface->surfaceList[1].width;
		dst_rect1.height= (guint) surface->surfaceList[1].height;


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


		NvBufSurfTransformParams nvbufsurface_params1;
		nvbufsurface_params1.src_rect = &src_rect1;
		nvbufsurface_params1.dst_rect = &dst_rect1;
		nvbufsurface_params1.transform_flag =  	NVBUFSURF_TRANSFORM_CROP_SRC |
										NVBUFSURF_TRANSFORM_CROP_DST;
		nvbufsurface_params1.transform_filter = NvBufSurfTransformInter_Default;


		NvBufSurface *dst_surface = NULL;
		NvBufSurface *dst_surface1 = NULL;
	
		NvBufSurfaceCreateParams nvbufsurface_create_params;

		/* An intermediate buffer for NV12/RGBA to BGR conversion  will be
		* required. Can be skipped if custom algorithm can work directly on NV12/RGBA. */
		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_RGBA;
		nvbufsurface_create_params.layout = NVBUF_LAYOUT_PITCH;
		nvbufsurface_create_params.memType = NVBUF_MEM_DEFAULT;

		NvBufSurfaceCreateParams nvbufsurface_create_params1;

		/* An intermediate buffer for NV12/RGBA to BGR conversion  will be
		* required. Can be skipped if custom algorithm can work directly on NV12/RGBA. */
		nvbufsurface_create_params1.gpuId  = surface->gpuId;
		nvbufsurface_create_params1.width  = (gint) surface->surfaceList[1].width;
		nvbufsurface_create_params1.height = (gint) surface->surfaceList[1].height;
		nvbufsurface_create_params1.size = 0;
		nvbufsurface_create_params1.colorFormat = NVBUF_COLOR_FORMAT_RGBA;
		nvbufsurface_create_params1.layout = NVBUF_LAYOUT_PITCH;
		nvbufsurface_create_params1.memType = NVBUF_MEM_DEFAULT;


		cuda_err = cudaSetDevice (surface->gpuId);

		cudaStream_t cuda_stream;

		cuda_err=cudaStreamCreate (&cuda_stream);

		int create_result = NvBufSurfaceCreate(&dst_surface,batch_size,
					&nvbufsurface_create_params);	

		create_result = NvBufSurfaceCreate(&dst_surface1,batch_size,
					&nvbufsurface_create_params1);	


		NvBufSurfTransformConfigParams transform_config_params;
		NvBufSurfTransform_Error err;

		transform_config_params.compute_mode = NvBufSurfTransformCompute_Default;
		transform_config_params.gpu_id = surface->gpuId;
		transform_config_params.cuda_stream = cuda_stream;
		err = NvBufSurfTransformSetSessionParams (&transform_config_params);

		NvBufSurfaceMemSet (dst_surface, 0, 0, 0);
		NvBufSurfaceMemSet (dst_surface1, 0, 0, 0);

		err = NvBufSurfTransform (surface, dst_surface, &nvbufsurface_params);
		if (err != NvBufSurfTransformError_Success) {
		g_print ("NvBufSurfTransform failed with error %d while converting buffer\n", err);
		}

		err = NvBufSurfTransform (surface, dst_surface1, &nvbufsurface_params1);
		if (err != NvBufSurfTransformError_Success) {
		g_print ("NvBufSurfTransform failed with error %d while converting buffer\n", err);
		}

		NvBufSurfaceMap (dst_surface, 0, 0, NVBUF_MAP_READ);
		NvBufSurfaceSyncForCpu (dst_surface, 0, 0);

		NvBufSurfaceMap (dst_surface1, 1, 0, NVBUF_MAP_READ);
		NvBufSurfaceSyncForCpu (dst_surface1, 1, 0);

		cv::Mat bgr_frame = cv::Mat (cv::Size(nvbufsurface_create_params.width,
					nvbufsurface_create_params.height), CV_8UC3);

		for(int cam_id=0; cam_id < batch_size;++cam_id)
		{
			cv::Mat in_mat;

			if(cam_id==0)
			{
				in_mat =
				cv::Mat (nvbufsurface_create_params.height, 
						nvbufsurface_create_params.width,
						CV_8UC4, dst_surface->surfaceList[cam_id].mappedAddr.addr[0],
						dst_surface->surfaceList[cam_id].pitch);
			}
			else if(cam_id==1)
			{
				in_mat =
				cv::Mat (nvbufsurface_create_params.height, 
						nvbufsurface_create_params.width,
						CV_8UC4, dst_surface1->surfaceList[cam_id].mappedAddr.addr[0],
						dst_surface1->surfaceList[cam_id].pitch);


			}
	
			cv::cvtColor (in_mat, bgr_frame, CV_RGBA2BGR);

			std::vector<uchar> encode_buffer;
			cv::imencode(".jpg",bgr_frame,encode_buffer);

			std::string encoded_jpeg;

			auto base64_jpeg = reinterpret_cast<const unsigned char*>
							(encode_buffer.data());
			encoded_jpeg = base64_encode(base64_jpeg, encode_buffer.size());
			frame_data.push_back(encoded_jpeg);		
		}

		NvBufSurfaceUnMap (dst_surface, 0, 0);
		NvBufSurfaceDestroy (dst_surface);
		NvBufSurfaceUnMap (dst_surface1, 1, 0);
		NvBufSurfaceDestroy (dst_surface);
		cudaStreamDestroy (cuda_stream);
		gst_buffer_unmap (buf, &in_map_info);

		#endif

		/*
		* Output KITTI labels with tracking ID if configured to do so.
		*/
		//write_kitti_track_output(appCtx, batch_meta);

		//write_db_kitti_track_output(appCtx, batch_meta, frame_data, timestamp);

	if (appCtx->primary_bbox_generated_cb)
	appCtx->primary_bbox_generated_cb (appCtx, buf, batch_meta, index);
	return GST_PAD_PROBE_OK;
}

I get the following error since buffer is null.

NvBufSurfTransform failed with error -3 while converting buffer

Please help me out.

Thanks

Hi,
Please check #23 to configure [tiled-display],[source*],[streammux], and [primary-gie]. You probably miss certain configs.

Hi DaneLLL,

I tried the configuration. Still does not work. I still get width and height of surface->surfaceList[1] 0.

Please guide me.

Thanks.

Hi,
We have verified either rtsp sources and video sources. Both work well. A bit strange you cannot run it. Please also try video sources by modifying uri in [source0] and [source1]:

uri=file://../../streams/sample_1080p_h264.mp4
#uri=rtsp://127.0.0.1:8554/test

Hi DaneLLL,

I can understand how to copy the entire NvBufSurface containing both the buffers (surfaceList[0] and surfaceList[1] ) to a destination surface (dst_surface). How to individually copy surfaceList[0] and surfaceList[1] to separate destination surfaces. Could you please help me out?

Thanks.

Hi,
Please check suggestion in #26

Hi. I’m trying to save the image from 8 different cameras. I have written a function to which I pass in_map_info and the stream id. I’m able to save the frames as jpg images however the source id and the frames saved don’t seem to match. For example, when I try to access surfaceList[3], I get a frame from some other source.

cv::Mat
  Mercury::getRGBFrame(GstMapInfo in_map_info, gint idx) {

    // To access the frame
    NvBufSurface *surface = NULL;
    NvBufSurface surface_idx;
    NvBufSurfTransformRect src_rect, dst_rect;

    surface = (NvBufSurface *) in_map_info.data;
    surface_idx = *surface;
    surface_idx.surfaceList = &(surface->surfaceList[idx]);
    surface_idx.numFilled = surface_idx.batchSize = 1;

    int batch_size = surface_idx.batchSize;
    src_rect.top   = 0;
    src_rect.left  = 0;
    src_rect.width = (guint) surface->surfaceList[idx].width;
    src_rect.height= (guint) surface->surfaceList[idx].height;

    dst_rect.top   = 0;
    dst_rect.left  = 0;
    dst_rect.width = (guint) surface->surfaceList[idx].width;
    dst_rect.height= (guint) surface->surfaceList[idx].height;

    NvBufSurfTransformParams nvbufsurface_params;
    nvbufsurface_params.src_rect = &src_rect;
    nvbufsurface_params.dst_rect = &dst_rect;
    nvbufsurface_params.transform_flag =  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  = (guint) surface->surfaceList[idx].width;
    nvbufsurface_create_params.height = (guint) surface->surfaceList[idx].height;
    nvbufsurface_create_params.size = 0;
    // nvbufsurface_create_params.isContiguous = true;
    nvbufsurface_create_params.colorFormat = NVBUF_COLOR_FORMAT_RGBA;
    nvbufsurface_create_params.layout = NVBUF_LAYOUT_PITCH;

    // THE memType PARAM IS SET TO CUDA UNIFIED IN dGPU DEVICES COMMENT IT out
    // AND USE THE IMMEDIATE NEXT LINE TO SET THE memType PARAM FOR JETSON DEVICES

    #ifdef PLATFORM_TEGRA
      nvbufsurface_create_params.memType = NVBUF_MEM_DEFAULT;
    #else
      nvbufsurface_create_params.memType = NVBUF_MEM_CUDA_UNIFIED;
    #endif

    cudaError_t cuda_err = cudaSetDevice (surface->gpuId);

    cudaStream_t cuda_stream;

    cuda_err = 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;
    transform_config_params.cuda_stream = cuda_stream;
    err = NvBufSurfTransformSetSessionParams (&transform_config_params);

    NvBufSurfaceMemSet (dst_surface, 0, 0, 0);

    err = NvBufSurfTransform (&surface_idx, dst_surface, &nvbufsurface_params);

    if (err != NvBufSurfTransformError_Success) {
      g_print ("NvBufSurfTransform failed with error %d while converting buffer\n", err);
    }

    NvBufSurfaceMap (dst_surface, 0, 0, NVBUF_MAP_READ);
    NvBufSurfaceSyncForCpu (dst_surface, 0, 0);

    cv::Mat bgr_frame = cv::Mat (cv::Size(nvbufsurface_create_params.width, nvbufsurface_create_params.height), CV_8UC3);

    cv::Mat in_mat = cv::Mat (nvbufsurface_create_params.height, nvbufsurface_create_params.width, CV_8UC4, dst_surface->surfaceList[0].mappedAddr.addr[0], dst_surface->surfaceList[0].pitch);

    #if (CV_VERSION_MAJOR >= 4)
      cv::cvtColor (in_mat, bgr_frame, COLOR_RGBA2BGR);
    #else
      cv::cvtColor (in_mat, bgr_frame, CV_RGBA2BGR);
    #endif

    NvBufSurfaceUnMap(dst_surface, 0 , 0);

    NvBufSurfaceDestroy(dst_surface);

    cudaStreamDestroy (cuda_stream);
    
    return bgr_frame;
  }

frame_meta->source_id - id of stream
frame_meta->batch_id - id surface of this stream in surfaceList