Hi,
We have the following use case: we use DeepStream to detect certain objects from a live source.
Then, when the object is detected, we would like to store a crop of the region around the object for further processing outside of DeepStream.
We have used the sample redaction_with_deepstream_app as a starting point, modifying the callback of the OSD plugin to implement cropping for the relevant objects.
Simultaneously, we want the ability to view the detections using an RTP stream. However, we face problems using the following pipeline:
v4l2src ! nvv4l2decoder ! nvvideoconvert ! ‘video/x-raw(NVMM), format=NV12’ ! nvstreammux ! queue ! nvinfer ! nvmultistream ! nvvideoconvert ! osd ! queue ! nvvideoconvert ! nvv4l2h264enc ! rtph264pay ! udpsink
One or two of the following errors occur, but only if an object is actually detected (thereby triggering the cropping operation):
- Segmentation fault (core dumped)
- Cuda failure: status=101
nvbufsurface: Error(-1) in releasing cuda memory
Segmentation fault (core dumped) - free invalid pointer
To crop the image, we create a new NvBufSurface object and then crop to it from the GstBuffer using NvBufSurfTransform.
We have a few questions:
1. Are we using the correct plugins, in the correct order, to set up an RTP stream like this? Or will the RTP stream be “corrupted” because it includes custom message data (the crop).
2. Are we doing the cropping in the right way, especially with regards to allocating and freeing memory for the surfaces?
The code for cropping the image is as follows:
NvBufSurface *crop_image(GstBuffer *buffer, NvOSD_RectParams *crop_rect_params) {
NvBufSurface *src_surface = NULL;
NvBufSurface *dst_surface = NULL;
NvBufSurfTransformRect src_rect;
NvBufSurfTransformRect dst_rect;
GstMapInfo in_map_info;
NvBufSurfaceCreateParams create_params;
NvBufSurfTransformParams transform_params;
memset(&in_map_info, 0, sizeof(in_map_info));
NvBufSurfTransform_Error transform_error;
if (!gst_buffer_map(buffer, &in_map_info, (GstMapFlags) (GST_MAP_READ | GST_MAP_WRITE))) {
g_printerr("Failed to map gst buffer.\n");
return NULL;
}
src_surface = (NvBufSurface *) in_map_info.data;
//TODO set to write class id
if (1) {
if (settings) {
int new_left = GST_ROUND_UP_2(crop_rect_params->left -settings->crop_margin);
if (new_left < 0) {
new_left = 0;
}
crop_rect_params->left = new_left;
int new_top = GST_ROUND_UP_2(crop_rect_params->top -settings->crop_margin);
if (new_top < 0) {
new_top = 0;
}
crop_rect_params->top = new_top;
int new_width = GST_ROUND_DOWN_2(crop_rect_params->width + 2 * settings->crop_margin);
if (new_left + new_width > 1280) {
new_width = 1280 - new_left;
}
crop_rect_params->width = new_width;
int new_height = GST_ROUND_DOWN_2(crop_rect_params->height + 2 * settings->crop_margin);
if (new_left + new_width > 1280) {
new_height = 1280 - new_top;
}
crop_rect_params->height = new_height;
} else {
crop_rect_params->left = GST_ROUND_UP_2(crop_rect_params->left);
crop_rect_params->top = GST_ROUND_UP_2(crop_rect_params->top);
crop_rect_params->width = GST_ROUND_DOWN_2(crop_rect_params->width);
crop_rect_params->height = GST_ROUND_DOWN_2(crop_rect_params->height);
}
src_rect.left = crop_rect_params->left;
src_rect.top = crop_rect_params->top;
src_rect.width = crop_rect_params->width;
src_rect.height = crop_rect_params->height;
dst_rect = {0, 0, (guint) src_rect.width, (guint) src_rect.height};
create_params.gpuId = 0;
create_params.width = src_rect.width;
create_params.height = src_rect.height;
create_params.size = 0;
create_params.colorFormat = NVBUF_COLOR_FORMAT_RGBA;
create_params.layout = NVBUF_LAYOUT_PITCH;
create_params.memType = NVBUF_MEM_CUDA_PINNED;
NvBufSurfaceCreate(&dst_surface, 1, &create_params);
dst_rect.left = 0;
dst_rect.top = 0;
dst_rect.width = src_rect.width;
dst_rect.height = src_rect.height;
// Set the transform parameters
transform_params.src_rect = &src_rect;
transform_params.dst_rect = &dst_rect;
transform_params.transform_flag = NVBUFSURF_TRANSFORM_CROP_SRC | NVBUFSURF_TRANSFORM_CROP_DST;
transform_params.transform_filter = NvBufSurfTransformInter_Default;
transform_error = NvBufSurfTransform(src_surface, dst_surface, &transform_params);
//TODO: NvBufSurfTransformError_Succes
if (transform_error != 0) {
g_printerr("NvBufSurfaceTransform failed with error %d while converting buffer.\n", transform_error);
}
}
gst_buffer_unmap(buffer, &in_map_info);
return dst_surface;
}
We also use a copy and free func:
static gpointer meta_copy_func (gpointer data, gpointer user_data)
{
NvDsUserMeta *user_meta = (NvDsUserMeta *) data;
NvDsEventMsgMeta *srcMeta = (NvDsEventMsgMeta *) user_meta->user_meta_data;
NvDsEventMsgMeta *dstMeta = NULL;
dstMeta = (NvDsEventMsgMeta *) g_memdup (srcMeta, sizeof(CustomObject));
if (srcMeta->ts)
dstMeta->ts = g_strdup (srcMeta->ts);
if(srcMeta->objClassId)
dstMeta->objClassId = srcMeta->objClassId;
if (srcMeta->extMsgSize > 0) {
// Allocate extra space in the message for custom message data
if (srcMeta->objType == NVDS_OBJECT_TYPE_VEHICLE) {
CustomObject *srcObj = (CustomObject *) srcMeta->extMsg;
CustomObject *obj = (CustomObject *) g_malloc0 (sizeof (CustomObject));
if (srcObj->frame)
obj->frame = srcObj->frame;
if (srcObj->vehicleObject) {
NvDsVehicleObject * newVehicleObj = (NvDsVehicleObject *) g_malloc0 (sizeof (NvDsVehicleObject));
obj->vehicleObject = newVehicleObj;
if (srcObj->vehicleObject->license)
obj->vehicleObject->license = g_strdup(srcObj->vehicleObject->license);
}
dstMeta->extMsg = obj;
dstMeta->extMsgSize = sizeof (NvDsVehicleObject);
}
}
if (user_meta->user_meta_data)
g_free(user_meta->user_meta_data);
return dstMeta;
}
static void meta_free_func (gpointer data, gpointer user_data)
{
NvDsUserMeta *user_meta = (NvDsUserMeta *) data;
NvDsEventMsgMeta *srcMeta = (NvDsEventMsgMeta *) user_meta->user_meta_data;
if (srcMeta->ts)
g_free (srcMeta->ts);
if(srcMeta->objClassId)
g_free (srcMeta->objectId);
// Free custom message data
if (srcMeta->extMsgSize > 0) {
if (srcMeta->objType == NVDS_OBJECT_TYPE_VEHICLE) {
CustomObject *obj = (CustomObject *) srcMeta->extMsg;
if (obj->frame)
NvBufSurfaceDestroy(obj->frame);
if (obj->vehicleObject) {
NvDsVehicleObject * vehicleObject = (NvDsVehicleObject *) obj->vehicleObject;
if (vehicleObject->license)
g_free (vehicleObject->license);
g_free(obj->vehicleObject);
}
}
g_free (srcMeta->extMsg);
srcMeta->extMsgSize = 0;
}
if (user_meta->user_meta_data)
g_free (user_meta->user_meta_data);
user_meta->user_meta_data = NULL;
}