Memory leak while attaching custom meta before streammux

Deepstream 6.2 dGPU

Im trying an app with app-src element. I have to read data form a redis queue for which I have written a sample read_data function as shown in the deepstream-appsrc-test app.
The redis queue contains base64 encoded images, I decode them and create GstBuffer out of them, and attach the image itself as a custom meta to the GstBuffer.

std::string rpopFromRedisQueue(const char *host, int port, const char *queueKey)
{
	redisContext *context = redisConnect(host, port);
	if (context == nullptr || context->err)
	{
		if (context)
		{
			std::cerr << "Connection error: " << context->errstr << std::endl;
			redisFree(context);
		}
		else
		{
			std::cerr << "Failed to allocate Redis context" << std::endl;
		}
		return nullptr;
	}
	redisReply *reply = static_cast<redisReply *>(redisCommand(context, "RPOP %s", queueKey));
	if (reply == nullptr)
	{
		std::cerr << "Failed to execute RPOP command" << std::endl;
		freeReplyObject(reply);
		redisFree(context);
		return nullptr;
	}
	std::string poppedValue = "None";
	if (reply->type == REDIS_REPLY_STRING && reply->str != nullptr)
	{
		poppedValue = reply->str;
	}
	else if (reply->type == REDIS_REPLY_NIL)
	{
		std::cout << "Queue " << queueKey << " is empty." << std::endl;
	}
	else
	{
		std::cerr << "Error executing RPOP: " << reply->str << std::endl;
	}
	freeReplyObject(reply);
	redisFree(context);
	return poppedValue;
}
gboolean read_data_new(AppSrcData *data2)
{
	std::string popped_value = rpopFromRedisQueue("192.168.134.243", 6379, "ENCAMERA");
	if (popped_value != "None")
	{
		nlohmann::json jsonData = nlohmann::json::parse(popped_value);
		if (!jsonData.is_discarded())
		{
			H264parseMeta *h264parse_meta =
				(H264parseMeta *)g_malloc0(sizeof(H264parseMeta));
			if (jsonData.contains("Imagename"))
			{
				h264parse_meta->parser_frame_num = jsonData["imageid"];
				h264parse_meta->base64_image_from_source = jsonData["img"];
				h264parse_meta->payload_name = jsonData["filename"];
			}
			// create a gstBuffer
			std::vector<uint8_t> decodedImage_ = base64Decode(jsonData["img"]);
			GstBuffer *gstBuffer = gst_buffer_new_allocate(nullptr, decodedImage_.size(), nullptr);
			gst_buffer_fill(gstBuffer, 0, decodedImage_.data(), decodedImage_.size());
			g_print("Buffer size: %lu\n", gst_buffer_get_size(gstBuffer));

  			// add custom meta to buffer
			NvDsMeta *meta = NULL;
			meta = gst_buffer_add_nvds_meta(gstBuffer, h264parse_meta, NULL,
											h264parse_meta_copy_func,
											h264parse_meta_release_func);

			meta->meta_type = (GstNvDsMetaType)NVDS_GST_META_BEFORE_DECODER_EXAMPLE;
			meta->gst_to_nvds_meta_transform_func =
				h264parse_gst_to_nvds_meta_transform_func;
			meta->gst_to_nvds_meta_release_func = h264parse_gst_nvds_meta_release_func;

			// push gstBuffer
			GstFlowReturn gstret = gst_app_src_push_buffer((GstAppSrc *)data2->app_source, gstBuffer);
			if (gstret != GST_FLOW_OK)
			{
				std::cout << "buffer could not be pushed" << std::endl;
			}
			if (gstret == GST_FLOW_OK)
			{
				std::cout << "buffer pushed" << std::endl;
			}
		}
	}
}

and made required changes in the metadata structure.

typedef struct _H264parseMeta
{
  guint parser_frame_num;
  std::string name = "";
  std::string payload_name = "";
  std::string base64_image_from_source = "none";
} H264parseMeta;

With this, Im the buffers are going in and im getting detections, however, this has a memory leak according to valgrind at these two lines.

h264parse_meta->base64_image_from_source = jsonData["img"];
h264parse_meta->payload_name = jsonData["filename"];

Im unsure why this is happening as im using the meta release function, which are,

static gpointer h264parse_meta_copy_func(gpointer data, gpointer user_data)
{
	H264parseMeta *src_h264parse_meta = (H264parseMeta *)data;
	H264parseMeta *dst_h264parse_meta =
		(H264parseMeta *)g_malloc0(sizeof(H264parseMeta));
	memcpy(dst_h264parse_meta, src_h264parse_meta, sizeof(H264parseMeta));
	return (gpointer)dst_h264parse_meta;
}

/* gst meta release function set by user */
static void h264parse_meta_release_func(gpointer data, gpointer user_data)
{
	H264parseMeta *h264parse_meta = (H264parseMeta *)data;
	if (h264parse_meta)
	{
		g_free(h264parse_meta);
		h264parse_meta = NULL;
	}
}

/* gst to nvds transform function set by user. "data" holds a pointer to
 * NvDsUserMeta */
static gpointer h264parse_gst_to_nvds_meta_transform_func(gpointer data,
														  gpointer user_data)
{
	NvDsUserMeta *user_meta = (NvDsUserMeta *)data;
	H264parseMeta *src_h264parse_meta =
		(H264parseMeta *)user_meta->user_meta_data;
	H264parseMeta *dst_h264parse_meta =
		(H264parseMeta *)h264parse_meta_copy_func(src_h264parse_meta, NULL);
	return (gpointer)dst_h264parse_meta;
}

/* release function set by user to release gst to nvds transformed metadata.
 * "data" holds a pointer to NvDsUserMeta */
static void h264parse_gst_nvds_meta_release_func(gpointer data,
												 gpointer user_data)
{
	NvDsUserMeta *user_meta = (NvDsUserMeta *)data;
	H264parseMeta *h264parse_meta = (H264parseMeta *)user_meta->user_meta_data;
	h264parse_meta_release_func(h264parse_meta, NULL);
}

can you point me in some direction ?

This is caused by the difference in memory layout between c language and cpp. You should change the code to the following

typedef struct _H264parseMeta
{
  guint parser_frame_num;
  std::string name = "";
  std::string payload_name = "";
  std::string base64_image_from_source = "none";
} H264parseMeta;

/* gst meta copy function set by user */
static gpointer h264parse_meta_copy_func(gpointer data, gpointer user_data)
{
  H264parseMeta *src_h264parse_meta = (H264parseMeta *)data;
  H264parseMeta *dst_h264parse_meta = new H264parseMeta();
  dst_h264parse_meta->parser_frame_num = src_h264parse_meta->parser_frame_num;
  dst_h264parse_meta->name = src_h264parse_meta->name;
  dst_h264parse_meta->payload_name = std::move(src_h264parse_meta->payload_name);
  dst_h264parse_meta->base64_image_from_source = std::move(src_h264parse_meta->base64_image_from_source);
  return (gpointer)dst_h264parse_meta;
}

/* gst meta release function set by user */
static void h264parse_meta_release_func(gpointer data, gpointer user_data)
{
  H264parseMeta *h264parse_meta = (H264parseMeta *)data;
  if(h264parse_meta) {
    delete h264parse_meta;
    h264parse_meta = NULL;
  }
}

after changing this, Im not able to access the attached custom meta on the probes.

for (l_user_meta = frame_meta->frame_user_meta_list; l_user_meta != NULL;
				 l_user_meta = l_user_meta->next)
			{
				user_meta = (NvDsUserMeta *)(l_user_meta->data);
				if (user_meta->base_meta.meta_type == NVDS_GST_META_BEFORE_DECODER_EXAMPLE)
				{
					h264parse_meta = (H264parseMeta *)user_meta->user_meta_data;
					if (h264parse_meta == nullptr)
					{
						std::cout << "MetaData Not found" << std::endl;
					}
					else
					{
						JFrame["payload_name"] = h264parse_meta->payload_name;
						JFrame["fov_image"] = h264parse_meta->base64_image_from_source;
						std::cout <<  "MetaData  found" << std::endl;
					}
				}
			}

1.Use new instead of g_malloc to construct cpp objects

H264parseMeta *h264parse_meta = new H264parseMeta();

I modified deepstream-appsrc-test according to your code, and it works fine.

Which element of the pipeline do you add the probe ?
Can you share a sample that reproduces your problem?

pipeline is

appsrc -> jpegparse -> nvv4l2decoder -> streammux -> nvinfer1 [face_detection_model] -> nvtracker -> queue1 -> queueu2 -> nvinfer2 [landmark estimation model] -> queue3 -> queue4 -> queue5 -> queue6 -> nvinfer3[face_recognition_model] -> nvvideoconvert -> osd -> sink

On nvinfer2 src pad I have the probe function that is trying to access that custom meta.

where Im trying to access like this

GstPadProbeReturn prediction_probe_low_latency(
	GstPad *pad, GstPadProbeInfo *info, gpointer u_data)
{
		GstBuffer *buf = (GstBuffer *)info->data;
		static guint use_device_mem = 0;
		H264parseMeta *h264parse_meta = NULL;
		NvDsMetaList *l_user_meta = NULL;
		NvDsUserMeta *user_meta = NULL;
		NvDsBatchMeta *batch_meta = gst_buffer_get_nvds_batch_meta(buf);
		NvDsDisplayMeta *display_meta = NULL;

		for (NvDsMetaList *l_frame = batch_meta->frame_meta_list; l_frame != NULL;
			 l_frame = l_frame->next)
		{
			json JFrame;
			NvDsFrameMeta *frame_meta = (NvDsFrameMeta *)l_frame->data;
			guint source_id_info = frame_meta->source_id;
			JFrame["stream_id"] = frame_meta->source_id;
			JFrame["frame_no"] = frame_meta->frame_num;
			for (l_user_meta = frame_meta->frame_user_meta_list; l_user_meta != NULL;
				 l_user_meta = l_user_meta->next)
			{
				user_meta = (NvDsUserMeta *)(l_user_meta->data);
				if (user_meta->base_meta.meta_type == NVDS_GST_META_BEFORE_DECODER_EXAMPLE)
				{
					h264parse_meta = (H264parseMeta *)user_meta->user_meta_data;
					if (h264parse_meta == nullptr)
					{
						std::cout << "MetaData Not found" << std::endl;
					}
					else
					{
						JFrame["payload_name"] = h264parse_meta->payload_name;
						JFrame["fov_image"] = h264parse_meta->base64_image_from_source;
						std::cout <<  "MetaData  found" << std::endl;
                   }
			    }
				
			}
       }
return GST_PAD_PROBE_OK;
}

this is where I access the custom metadata.

Based on deepstream-gst-metadata-test, referring to your pipeline,
metadata can be obtained normally.

Can you share a sample and configuration file that can reproduce the problem?

after implementing the changes that you mentioned, the memory leak seems to be gone. We can close this topic I guess.
thanks for the help

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