Drawing Line on top of video using NvDsLineMeta

I wish to draw a few lines on top of video using NvDsLineMeta. I tested it with deepstream-test1-app by inserting the line information manually to NvDsLineMeta. It doesn’t work like what I expect. May I know how we draw a line with NvDsLineMeta without creating a new plugin.

#include <gst/gst.h>
#include <glib.h>

#include "gstnvdsmeta.h"

#define MAX_DISPLAY_LEN 64

#define PGIE_CLASS_ID_VEHICLE 0
#define PGIE_CLASS_ID_PERSON 2

gint frame_number = 0;
gchar pgie_classes_str[4][32] = { "Vehicle", "TwoWheeler", "Person",
  "Roadsign"
};

/* osd_sink_pad_buffer_probe  will extract metadata received on OSD sink pad
 * and update params for drawing rectangle, object information etc. */

static void generate_line_meta(gpointer data)
{ guint l_index, num_lines;
  //NvOSD_LineParams *line_param = NULL;
  
  NvDsLineMeta *meta = (NvDsLineMeta *) data;
  meta->num_lines = 1.0;
  meta->batch_id = 1.0;
  num_lines = meta->num_lines;
  
  NvOSD_LineParams *line_param = (NvOSD_LineParams *) g_malloc0 (sizeof (NvOSD_LineParams));
  meta->line_params[0] = g_malloc0 (sizeof (NvOSD_LineParams));
  meta->line_params[1] = g_malloc0 (sizeof (NvOSD_LineParams));
  //line_param = & (meta->line_params[0]);
  line_param = g_malloc0 (sizeof (NvOSD_LineParams)); 
  //g_print("x1 = %d \n", line_param->x1);
  line_param->x1 = 100;
  // //g_print ("Linex1 b4 = %d \n", line_param->x1 );
  line_param->y1 = 100;
  line_param->x2 = 400;
  line_param->y2 = 400;
  line_param->line_width = 10;
  line_param->line_color.red = 1.0;
  line_param->line_color.green = 0.0;
  line_param->line_color.blue = 0.0;
  line_param->line_color.alpha = 1.0;

  meta->line_params[0] = line_param;
  meta->line_params[1] = line_param;

  //g_print ("Test %d\n", meta->line_params[0].x1);
}


static GstPadProbeReturn
osd_sink_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer u_data)
{

  GstMeta *gst_meta = NULL;
  NvDsMeta *nvdsmeta = NULL;
  gpointer state = NULL;
  static GQuark _nvdsmeta_quark = 0;    
  GstBuffer *buf = (GstBuffer *) info->data;   //Put all the data from the probe to GstBuffer buf
  NvDsFrameMeta *frame_meta = NULL;
  NvDsLineMeta *line_meta = NULL;
  guint num_rects = 0, rect_index = 0;
  NvDsObjectParams *obj_meta = NULL;
  NvOSD_LineParams *line_param = NULL;
  guint i = 0;
  NvOSD_TextParams *txt_params = NULL;
  guint vehicle_count = 0;
  guint person_count = 0;

  if (!_nvdsmeta_quark)
    _nvdsmeta_quark = g_quark_from_static_string (NVDS_META_STRING);   //NVDS_META_STRING = nvdsmeta, get a quark from nvdsmeta, if NULL, create a new quark to nvdsmeta.

  while ((gst_meta = gst_buffer_iterate_meta (buf, &state))) {         //&state = NULL, Get the the gst_meta from the current buffer. Iterate the buffer to get NvDsMeta.
    if (gst_meta_api_type_has_tag (gst_meta->info->api, _nvdsmeta_quark)) {    //To find the gst_meta with quark tag (nvdsmeta), so that it return TRUE for nvdsmeta.

      nvdsmeta = (NvDsMeta *) gst_meta;                                  

      /* We are interested only in intercepting Meta of type
       * "NVDS_META_FRAME_INFO" as they are from our infer elements. */
      if (nvdsmeta->meta_type == NVDS_META_FRAME_INFO) {          //There are still alot of information from NvDsMeta nvdsmeta, set meta_type to NVDS_META_FRAME_INFO only
        frame_meta = (NvDsFrameMeta *) nvdsmeta->meta_data;       //Set nvdsmeta->(gpointer)meta_data to frame_meta.
        if (frame_meta == NULL) {
          g_print ("NvDsFrameMeta contained NULL meta \n");
          return GST_PAD_PROBE_OK;
        }

        /* We reset the num_strings here as we plan to iterate through the
         *  the detected objects and form our own strings.
         *  The pipeline generated strings shall be discarded.
         */
        frame_meta->num_strings = 0;

        num_rects = frame_meta->num_rects;
        

        /* This means we have num_rects in frame_meta->obj_params,
         * now lets iterate through them */

        for (rect_index = 0; rect_index < num_rects; rect_index++) {
          /* Now using above information we need to form a text that should
           * be displayed on top of the bounding box, so lets form it here. */

          obj_meta = (NvDsObjectParams *) & frame_meta->obj_params[rect_index];

          txt_params = &(obj_meta->text_params);
          /*
          if (txt_params->display_text)
            g_free (txt_params->display_text);

          txt_params->display_text = g_malloc0 (MAX_DISPLAY_LEN);

          g_snprintf (txt_params->display_text, MAX_DISPLAY_LEN, "%s %d",
              pgie_classes_str[obj_meta->class_id], obj_meta->tracking_id );*/

          if (obj_meta->class_id == PGIE_CLASS_ID_VEHICLE)
            vehicle_count++;
          if (obj_meta->class_id == PGIE_CLASS_ID_PERSON)
            person_count++;

          /* Now set the offsets where the string should appear */
          txt_params->x_offset = obj_meta->rect_params.left;
          txt_params->y_offset = obj_meta->rect_params.top - 25;

          /* Font , font-color and font-size */
          txt_params->font_params.font_name = "Arial";
        
          txt_params->font_params.font_size = 10;
          txt_params->font_params.font_color.red = 1.0;
          txt_params->font_params.font_color.green = 1.0;
          txt_params->font_params.font_color.blue = 1.0;
          txt_params->font_params.font_color.alpha = 1.0;

          /* Text background color */
          txt_params->set_bg_clr = 1;
          txt_params->text_bg_clr.red = 0.0;
          txt_params->text_bg_clr.green = 0.0;
          txt_params->text_bg_clr.blue = 0.0;
          txt_params->text_bg_clr.alpha = 1.0;

          frame_meta->num_strings++;
        }
      }

      NvDsMeta *gst_line_meta = NULL;
      NvDsLineMeta *line_meta = (NvDsLineMeta *) g_malloc0 (sizeof (NvDsLineMeta));
      generate_line_meta (line_meta);
      //g_print ("line = %d\n", line_meta->line_params[0]->x1);
      gst_line_meta = gst_buffer_add_nvds_meta (buf, line_meta, NULL);

      if (nvdsmeta->meta_type == NVDS_META_LINE_INFO)
         g_print ("In2\n");
      //g_print ("In2\n");   
    
    }
  }
  /*g_print ("Frame Number = %d Number of objects = %d "
      "Vehicle Count = %d Person Count = %d\n",
      frame_number, num_rects, vehicle_count, person_count);*/
  frame_number++;

  return GST_PAD_PROBE_OK;
}

static gboolean
bus_call (GstBus * bus, GstMessage * msg, gpointer data)
{
  GMainLoop *loop = (GMainLoop *) data;
  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_EOS:
      g_print ("End of stream\n");
      g_main_loop_quit (loop);
      break;
    case GST_MESSAGE_ERROR:{
      gchar *debug;
      GError *error;
      gst_message_parse_error (msg, &error, &debug);
      g_printerr ("ERROR from element %s: %s\n",
          GST_OBJECT_NAME (msg->src), error->message);
      if (debug)
        g_printerr ("Error details: %s\n", debug);
      g_free (debug);
      g_error_free (error);
      g_main_loop_quit (loop);
      break;
    }
    default:
      break;
  }
  return TRUE;
}

int
main (int argc, char *argv[])
{
  GMainLoop *loop = NULL;
  GstElement *pipeline = NULL, *source = NULL, *h264parser = NULL,
      *decoder = NULL, *sink = NULL, *pgie = NULL, *nvvidconv = NULL, *dsexample = NULL,
      *nvosd = NULL, *tracker = NULL;
  GstBus *bus = NULL;
  guint bus_watch_id;
  gulong osd_probe_id = 0;
  GstPad *osd_sink_pad = NULL;

  /* Check input arguments */
  if (argc != 2) {
    g_printerr ("Usage: %s <H264 filename>\n", argv[0]);
    return -1;
  }

  /* Standard GStreamer initialization */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

  /* Create gstreamer elements */
  /* Create Pipeline element that will form a connection of other elements */
  pipeline = gst_pipeline_new ("dstest1-pipeline");

  /* Source element for reading from the file */
  source = gst_element_factory_make ("filesrc", "file-source");

  /* Since the data format in the input file is elementary h264 stream,
   * we need a h264parser */
  h264parser = gst_element_factory_make ("h264parse", "h264-parser");

  /* Use nvdec_h264 for hardware accelerated decode on GPU */
  decoder = gst_element_factory_make ("nvdec_h264", "nvh264-decoder");

  /* Use nvinfer to run inferencing on decoder's output,
   * behaviour of inferencing is set through config file */
  pgie = gst_element_factory_make ("nvinfer", "primary-nvinference-engine");

  /* Use nvtracker to tracker the result*/
  tracker = gst_element_factory_make ("nvtracker", "nvidia-tracker");

  /* Use convertor to convert from NV12 to RGBA as required by nvosd */
  nvvidconv = gst_element_factory_make ("nvvidconv", "nvvideo-converter");

    /* Use convertor to convert from NV12 to RGBA as required by nvosd */
  //dsexample = gst_element_factory_make ("cairo", "dsexample_testing");

  /* Create OSD to draw on the converted RGBA buffer */
  nvosd = gst_element_factory_make ("nvosd", "nv-onscreendisplay");

  /* Finally render the osd output */
  sink = gst_element_factory_make ("nveglglessink", "nvvideo-renderer");

  if (!pipeline || !source || !h264parser || !decoder || !pgie || !tracker
      || !nvvidconv || !nvosd || !sink) {
    g_printerr ("One element could not be created. Exiting.\n");
    return -1;
  }

  /* we set the input filename to the source element */
  g_object_set (G_OBJECT (source), "location", argv[1], NULL);

  /* Set all the necessary properties of the nvinfer element,
   * the necessary ones are : */
  g_object_set (G_OBJECT (pgie),
      "config-file-path", "dstest1_pgie_config.txt", NULL);

  /* we set the input tracking configuration into tracking element */
  g_object_set (G_OBJECT (tracker), "tracker-width", 640, "tracker-height", 368, 
  "tracker-algorithm", 1, "iou-threshold", 0.9, NULL);

  //g_object_set (G_OBJECT (dsexample), "full-frame", 1, NULL);

  /* we set the osd properties here */
  //g_object_set (G_OBJECT (nvosd), "font-size", 45, NULL);

  /* we add a message handler */
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  /* Set up the pipeline */
  /* we add all elements into the pipeline */
  gst_bin_add_many (GST_BIN (pipeline),
      source, h264parser, decoder, pgie, tracker,
      nvvidconv, nvosd, sink, NULL);

  /* we link the elements together */
  /* file-source -> h264-parser -> nvh264-decoder ->
   * nvinfer -> nvtracker -> nvvidconv -> nvosd -> video-renderer */
  if (!gst_element_link_many (source, h264parser, decoder, pgie, tracker,
      nvvidconv, nvosd, sink, NULL)) {
    g_printerr ("Elements could not be linked. Exiting.\n");
    return -1;
  }

  /* Lets add probe to get informed of the meta data generated, we add probe to
   * the sink pad of the osd element, since by that time, the buffer would have
   * had got all the metadata. */
  osd_sink_pad = gst_element_get_static_pad (nvosd, "sink");
  if (!osd_sink_pad)
    g_print ("Unable to get sink pad\n");
  else
    osd_probe_id = gst_pad_add_probe (osd_sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
        osd_sink_pad_buffer_probe, NULL, NULL);

  /* Set the pipeline to "playing" state */
  g_print ("Now playing: %s\n", argv[1]);
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  /* Wait till pipeline encounters an error or EOS */
  g_print ("Running...\n");
  g_main_loop_run (loop);

  /* Out of the main loop, clean up nicely */
  g_print ("Returned, stopping playback\n");
  gst_element_set_state (pipeline, GST_STATE_NULL);
  g_print ("Deleting pipeline\n");
  gst_object_unref (GST_OBJECT (pipeline));
  g_source_remove (bus_watch_id);
  g_main_loop_unref (loop);
  return 0;


}
{
          NvDsLineMeta *line_meta =<b> malloc and fill your data</b>
  
          meta = gst_buffer_add_nvds_meta (GstBuffer, (void *) line_meta,
                                               (GDestroyNotify) nvds_free_line_info);
          if (meta) {
            meta->meta_type = NVDS_META_LINE_INFO;
          }
        }

I think you can add this code to “osd_sink_pad_buffer_probe”

Hi Chris,

Thank you for your reply. I tried it but there is error. My objective is to add one or two lines and visualize the lines in the video. I generate line coordinate and put it in NvDsLineMeta. Will nvosd draw out the line like how nvosd do for bounding box.

Regards and thank you,
Nero

/*
 * Copyright (c) 2018 NVIDIA Corporation.  All rights reserved.
 *
 * NVIDIA Corporation and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA Corporation is strictly prohibited.
 *
 */

#include <gst/gst.h>
#include <glib.h>

#include "gstnvdsmeta.h"

#define MAX_DISPLAY_LEN 64

#define PGIE_CLASS_ID_VEHICLE 0
#define PGIE_CLASS_ID_PERSON 2

gint frame_number = 0;
gchar pgie_classes_str[4][32] = { "Vehicle", "TwoWheeler", "Person",
  "Roadsign"
};

/* osd_sink_pad_buffer_probe  will extract metadata received on OSD sink pad
 * and update params for drawing rectangle, object information etc. */

static void generate_line_meta(gpointer data)
{ guint l_index, num_lines;
  //NvOSD_LineParams *line_param = NULL;
  
  NvDsLineMeta *meta = (NvDsLineMeta *) data;
  meta->num_lines = 1.0;
  meta->batch_id = 1.0;
  num_lines = meta->num_lines;
  
  NvOSD_LineParams *line_param = (NvOSD_LineParams *) g_malloc0 (sizeof (NvOSD_LineParams));
  meta->line_params = g_malloc0 (sizeof (NvOSD_LineParams));
  line_param = g_malloc0 (sizeof (NvOSD_LineParams)); 
  line_param->x1 = 100;
  line_param->y1 = 100;
  line_param->x2 = 400;
  line_param->y2 = 400;
  line_param->line_width = 10;
  line_param->line_color.red = 1.0;
  line_param->line_color.green = 0.0;
  line_param->line_color.blue = 0.0;
  line_param->line_color.alpha = 1.0;

  meta->line_params= line_param;

  //g_print ("Test %d\n", meta->line_params[0].x1);
}

static GstPadProbeReturn
osd_sink_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer u_data)
{

  GstMeta *gst_meta = NULL;
  NvDsMeta *nvdsmeta = NULL;
  gpointer state = NULL;
  static GQuark _nvdsmeta_quark = 0;    
  GstBuffer *buf = (GstBuffer *) info->data;   //Put all the data from the probe to GstBuffer buf
  NvDsFrameMeta *frame_meta = NULL;
  NvDsLineMeta *line_meta = NULL;
  guint num_rects = 0, rect_index = 0;
  NvDsObjectParams *obj_meta = NULL;
  NvOSD_LineParams *line_param = NULL;
  guint i = 0;
  NvOSD_TextParams *txt_params = NULL;
  guint vehicle_count = 0;
  guint person_count = 0;

  if (!_nvdsmeta_quark)
    _nvdsmeta_quark = g_quark_from_static_string (NVDS_META_STRING);   //NVDS_META_STRING = nvdsmeta, get a quark from nvdsmeta, if NULL, create a new quark to nvdsmeta.

  while ((gst_meta = gst_buffer_iterate_meta (buf, &state))) {         //&state = NULL, Get the the gst_meta from the current buffer. Iterate the buffer to get NvDsMeta.
    if (gst_meta_api_type_has_tag (gst_meta->info->api, _nvdsmeta_quark)) {    //To find the gst_meta with quark tag (nvdsmeta), so that it return TRUE for nvdsmeta.

      nvdsmeta = (NvDsMeta *) gst_meta;                                  

      /* We are interested only in intercepting Meta of type
       * "NVDS_META_FRAME_INFO" as they are from our infer elements. */
      if (nvdsmeta->meta_type == NVDS_META_FRAME_INFO) {          //There are still alot of information from NvDsMeta nvdsmeta, set meta_type to NVDS_META_FRAME_INFO only
        frame_meta = (NvDsFrameMeta *) nvdsmeta->meta_data;       //Set nvdsmeta->(gpointer)meta_data to frame_meta.
        if (frame_meta == NULL) {
          g_print ("NvDsFrameMeta contained NULL meta \n");
          return GST_PAD_PROBE_OK;
        }

        /* We reset the num_strings here as we plan to iterate through the
         *  the detected objects and form our own strings.
         *  The pipeline generated strings shall be discarded.
         */
        frame_meta->num_strings = 0;

        num_rects = frame_meta->num_rects;

/* This means we have num_rects in frame_meta->obj_params,
         * now lets iterate through them */

        for (rect_index = 0; rect_index < num_rects; rect_index++) {
          /* Now using above information we need to form a text that should
           * be displayed on top of the bounding box, so lets form it here. */

          obj_meta = (NvDsObjectParams *) & frame_meta->obj_params[rect_index];

          txt_params = &(obj_meta->text_params);
          /*
          if (txt_params->display_text)
            g_free (txt_params->display_text);

          txt_params->display_text = g_malloc0 (MAX_DISPLAY_LEN);

          g_snprintf (txt_params->display_text, MAX_DISPLAY_LEN, "%s %d",
              pgie_classes_str[obj_meta->class_id], obj_meta->tracking_id );*/

          if (obj_meta->class_id == PGIE_CLASS_ID_VEHICLE)
            vehicle_count++;
          if (obj_meta->class_id == PGIE_CLASS_ID_PERSON)
            person_count++;

          /* Now set the offsets where the string should appear */
          txt_params->x_offset = obj_meta->rect_params.left;
          txt_params->y_offset = obj_meta->rect_params.top - 25;

          /* Font , font-color and font-size */
          txt_params->font_params.font_name = "Arial";
        
          txt_params->font_params.font_size = 10;
          txt_params->font_params.font_color.red = 1.0;
          txt_params->font_params.font_color.green = 1.0;
          txt_params->font_params.font_color.blue = 1.0;
          txt_params->font_params.font_color.alpha = 1.0;

          /* Text background color */
          txt_params->set_bg_clr = 1;
          txt_params->text_bg_clr.red = 0.0;
          txt_params->text_bg_clr.green = 0.0;
          txt_params->text_bg_clr.blue = 0.0;
          txt_params->text_bg_clr.alpha = 1.0;

          frame_meta->num_strings++;
        }
      }

      NvDsMeta *gst_line_meta = NULL;
      NvDsLineMeta *line_meta = (NvDsLineMeta *) g_malloc0 (sizeof (NvDsLineMeta));
      generate_line_meta (line_meta);
      g_print ("line = %d\n", line_meta->line_params->x1);
      gst_line_meta = gst_buffer_add_nvds_meta (buf, (void*)line_meta, (GDestroyNotify)nvds_free_line_info);

      if (gst_line_meta)
      {
        nvdsmeta->meta_type = NVDS_META_LINE_INFO;
      }
    
    }
  }
  /*g_print ("Frame Number = %d Number of objects = %d "
      "Vehicle Count = %d Person Count = %d\n",
      frame_number, num_rects, vehicle_count, person_count);*/
  frame_number++;

  return GST_PAD_PROBE_OK;
}

static gboolean
bus_call (GstBus * bus, GstMessage * msg, gpointer data)
{
  GMainLoop *loop = (GMainLoop *) data;
  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_EOS:
      g_print ("End of stream\n");
      g_main_loop_quit (loop);
      break;
    case GST_MESSAGE_ERROR:{
      gchar *debug;
      GError *error;
      gst_message_parse_error (msg, &error, &debug);
      g_printerr ("ERROR from element %s: %s\n",
          GST_OBJECT_NAME (msg->src), error->message);
      if (debug)
        g_printerr ("Error details: %s\n", debug);
      g_free (debug);
      g_error_free (error);
      g_main_loop_quit (loop);
      break;
    }
    default:
      break;
  }
  return TRUE;
}

int
main (int argc, char *argv[])
{
  GMainLoop *loop = NULL;
  GstElement *pipeline = NULL, *source = NULL, *h264parser = NULL,
      *decoder = NULL, *sink = NULL, *pgie = NULL, *nvvidconv = NULL, *dsexample = NULL,
      *nvosd = NULL, *tracker = NULL;
  GstBus *bus = NULL;
  guint bus_watch_id;
  gulong osd_probe_id = 0;
  GstPad *osd_sink_pad = NULL;

  /* Check input arguments */
  if (argc != 2) {
    g_printerr ("Usage: %s <H264 filename>\n", argv[0]);
    return -1;
  }

  /* Standard GStreamer initialization */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

  /* Create gstreamer elements */
  /* Create Pipeline element that will form a connection of other elements */
  pipeline = gst_pipeline_new ("dstest1-pipeline");

  /* Source element for reading from the file */
  source = gst_element_factory_make ("filesrc", "file-source");

  /* Since the data format in the input file is elementary h264 stream,
   * we need a h264parser */
  h264parser = gst_element_factory_make ("h264parse", "h264-parser");

  /* Use nvdec_h264 for hardware accelerated decode on GPU */
  decoder = gst_element_factory_make ("nvdec_h264", "nvh264-decoder");

  /* Use nvinfer to run inferencing on decoder's output,
   * behaviour of inferencing is set through config file */
  pgie = gst_element_factory_make ("nvinfer", "primary-nvinference-engine");

  /* Use nvtracker to tracker the result*/
  tracker = gst_element_factory_make ("nvtracker", "nvidia-tracker");

  /* Use convertor to convert from NV12 to RGBA as required by nvosd */
  nvvidconv = gst_element_factory_make ("nvvidconv", "nvvideo-converter");

    /* Use convertor to convert from NV12 to RGBA as required by nvosd */
  //dsexample = gst_element_factory_make ("cairo", "dsexample_testing");

  /* Create OSD to draw on the converted RGBA buffer */
  nvosd = gst_element_factory_make ("nvosd", "nv-onscreendisplay");

  /* Finally render the osd output */
  sink = gst_element_factory_make ("nveglglessink", "nvvideo-renderer");

  if (!pipeline || !source || !h264parser || !decoder || !pgie || !tracker
      || !nvvidconv || !nvosd || !sink) {
    g_printerr ("One element could not be created. Exiting.\n");
    return -1;
  }

  /* we set the input filename to the source element */
  g_object_set (G_OBJECT (source), "location", argv[1], NULL);

  /* Set all the necessary properties of the nvinfer element,
   * the necessary ones are : */
  g_object_set (G_OBJECT (pgie),
      "config-file-path", "dstest1_pgie_config.txt", NULL);

  /* we set the input tracking configuration into tracking element */
  g_object_set (G_OBJECT (tracker), "tracker-width", 640, "tracker-height", 368, 
  "tracker-algorithm", 1, "iou-threshold", 0.9, NULL);

  //g_object_set (G_OBJECT (dsexample), "full-frame", 1, NULL);

  /* we set the osd properties here */
  //g_object_set (G_OBJECT (nvosd), "font-size", 45, NULL);

  /* we add a message handler */
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  /* Set up the pipeline */
  /* we add all elements into the pipeline */
  gst_bin_add_many (GST_BIN (pipeline),
      source, h264parser, decoder, pgie, tracker,
      nvvidconv, nvosd, sink, NULL);

  /* we link the elements together */
  /* file-source -> h264-parser -> nvh264-decoder ->
   * nvinfer -> nvtracker -> nvvidconv -> nvosd -> video-renderer */
  if (!gst_element_link_many (source, h264parser, decoder, pgie, tracker,
      nvvidconv, nvosd, sink, NULL)) {
    g_printerr ("Elements could not be linked. Exiting.\n");
    return -1;
  }

  /* Lets add probe to get informed of the meta data generated, we add probe to
   * the sink pad of the osd element, since by that time, the buffer would have
   * had got all the metadata. */
  osd_sink_pad = gst_element_get_static_pad (nvosd, "sink");
  if (!osd_sink_pad)
    g_print ("Unable to get sink pad\n");
  else
    osd_probe_id = gst_pad_add_probe (osd_sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
        osd_sink_pad_buffer_probe, NULL, NULL);

  /* Set the pipeline to "playing" state */
  g_print ("Now playing: %s\n", argv[1]);
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  /* Wait till pipeline encounters an error or EOS */
  g_print ("Running...\n");
  g_main_loop_run (loop);

  /* Out of the main loop, clean up nicely */
  g_print ("Returned, stopping playback\n");
  gst_element_set_state (pipeline, GST_STATE_NULL);
  g_print ("Deleting pipeline\n");
  gst_object_unref (GST_OBJECT (pipeline));
  g_source_remove (bus_watch_id);
  g_main_loop_unref (loop);
  return 0;

}

Hi Chris,

I fixed the errors. The line coordinates is added to gst_buffer. The code is running but the line is not drawn on the video. Will NvOSD draw the line by getting details from NvDsLineMeta?

/*
 * Copyright (c) 2018 NVIDIA Corporation.  All rights reserved.
 *
 * NVIDIA Corporation and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA Corporation is strictly prohibited.
 *
 */

#include <gst/gst.h>
#include <glib.h>

#include "gstnvdsmeta.h"

#define MAX_DISPLAY_LEN 64

#define PGIE_CLASS_ID_VEHICLE 0
#define PGIE_CLASS_ID_PERSON 2

gint frame_number = 0;
gchar pgie_classes_str[4][32] = { "Vehicle", "TwoWheeler", "Person",
  "Roadsign"
};


static void generate_line_meta(gpointer data)
{ guint l_index, num_lines;
  
  NvDsLineMeta *meta = (NvDsLineMeta *) data;
  meta->num_lines = 1.0;
  meta->batch_id = 1.0;
  num_lines = meta->num_lines;
  
  NvOSD_LineParams *line_param = (NvOSD_LineParams *) g_malloc0 (sizeof (NvOSD_LineParams));
  meta->line_params = g_malloc0 (sizeof (NvOSD_LineParams));
  line_param = g_malloc0 (sizeof (NvOSD_LineParams)); 
  line_param->x1 = 100;
  line_param->y1 = 100;
  line_param->x2 = 400;
  line_param->y2 = 400;
  line_param->line_width = 10;
  line_param->line_color.red = 1.0;
  line_param->line_color.green = 0.0;
  line_param->line_color.blue = 0.0;
  line_param->line_color.alpha = 1.0;

  meta->line_params= line_param;

  //g_print ("Test %d\n", meta->line_params[0].x1);
}



/* osd_sink_pad_buffer_probe  will extract metadata received on OSD sink pad
 * and update params for drawing rectangle, object information etc. */

static GstPadProbeReturn
osd_sink_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer u_data)
{

  GstMeta *gst_meta = NULL;
  NvDsMeta *nvdsmeta = NULL;
  gpointer state = NULL;
  static GQuark _nvdsmeta_quark = 0;    
  GstBuffer *buf = (GstBuffer *) info->data;   //Put all the data from the probe to GstBuffer buf
  NvDsFrameMeta *frame_meta = NULL;
  guint num_rects = 0, rect_index = 0, l_index = 0;
  NvDsObjectParams *obj_meta = NULL;
  guint i = 0;
  NvOSD_TextParams *txt_params = NULL;
  guint vehicle_count = 0;
  guint person_count = 0;
  gboolean is_first_rect = TRUE;

  if (!_nvdsmeta_quark)
    _nvdsmeta_quark = g_quark_from_static_string (NVDS_META_STRING);   //NVDS_META_STRING = nvdsmeta, get a quark from nvdsmeta, if NULL, create a new quark to nvdsmeta.

  while ((gst_meta = gst_buffer_iterate_meta (buf, &state))) {         //&state = NULL, Get the the gst_meta from the current buffer. Iterate the buffer to get NvDsMeta.
    if (gst_meta_api_type_has_tag (gst_meta->info->api, _nvdsmeta_quark)) {    //To find the gst_meta with quark tag (nvdsmeta), so that it return TRUE for nvdsmeta.

      nvdsmeta = (NvDsMeta *) gst_meta;                                  

      /* We are interested only in intercepting Meta of type
       * "NVDS_META_FRAME_INFO" as they are from our infer elements. */
      if (nvdsmeta->meta_type == NVDS_META_FRAME_INFO) {          //There are still alot of information from NvDsMeta nvdsmeta, set meta_type to NVDS_META_FRAME_INFO only
        frame_meta = (NvDsFrameMeta *) nvdsmeta->meta_data;       //Set nvdsmeta->(gpointer)meta_data to frame_meta.
        if (frame_meta == NULL) {
          g_print ("NvDS Meta contained NULL meta \n");
          return GST_PAD_PROBE_OK;
        }

        /* We reset the num_strings here as we plan to iterate through the
         *  the detected objects and form our own strings.
         *  The pipeline generated strings shall be discarded.
         */
        frame_meta->num_strings = 0;

        num_rects = frame_meta->num_rects;
        is_first_rect = TRUE;

        /* This means we have num_rects in frame_meta->obj_params,
         * now lets iterate through them */

        for (rect_index = 0; rect_index < num_rects; rect_index++) {
          /* Now using above information we need to form a text that should
           * be displayed on top of the bounding box, so lets form it here. */

          obj_meta = (NvDsObjectParams *) & frame_meta->obj_params[rect_index];

          txt_params = &(obj_meta->text_params);
          if (txt_params->display_text)
            g_free (txt_params->display_text);

          txt_params->display_text = g_malloc0 (MAX_DISPLAY_LEN);

          g_snprintf (txt_params->display_text, MAX_DISPLAY_LEN, "%s %d",
              pgie_classes_str[obj_meta->class_id], obj_meta->tracking_id );

          if (obj_meta->class_id == PGIE_CLASS_ID_VEHICLE)
            vehicle_count++;
          if (obj_meta->class_id == PGIE_CLASS_ID_PERSON)
            person_count++;

          /* Now set the offsets where the string should appear */
          txt_params->x_offset = obj_meta->rect_params.left;
          txt_params->y_offset = obj_meta->rect_params.top - 25;

          /* Font , font-color and font-size */
          txt_params->font_params.font_name = "Arial";
          txt_params->font_params.font_size = 10;
          txt_params->font_params.font_color.red = 1.0;
          txt_params->font_params.font_color.green = 1.0;
          txt_params->font_params.font_color.blue = 1.0;
          txt_params->font_params.font_color.alpha = 1.0;

          /* Text background color */
          txt_params->set_bg_clr = 1;
          txt_params->text_bg_clr.red = 0.0;
          txt_params->text_bg_clr.green = 0.0;
          txt_params->text_bg_clr.blue = 0.0;
          txt_params->text_bg_clr.alpha = 1.0;

          frame_meta->num_strings++;

          NvDsMeta *gst_line_meta = NULL;
          NvDsLineMeta *line_meta = (NvDsLineMeta *) g_malloc0 (sizeof (NvDsEventMsgMeta));
          generate_line_meta (line_meta);
          gst_line_meta = gst_buffer_add_nvds_meta (buf, (void*)line_meta, (GDestroyNotify)nvds_free_line_info);
          if (gst_line_meta) {
            gst_line_meta->meta_type = NVDS_META_LINE_INFO;

          } else {
            g_print ("Error in attaching event meta to buffer\n");
          }
          
        }
      }
    }
  }
  /*
  g_print ("Frame Number = %d Number of objects = %d "
      "Vehicle Count = %d Person Count = %d  Line_Present = %d\n",
      frame_number, num_rects, vehicle_count, person_count, obj_meta->lines_present);*/
  frame_number++;

  return GST_PAD_PROBE_OK;
}

static gboolean
bus_call (GstBus * bus, GstMessage * msg, gpointer data)
{
  GMainLoop *loop = (GMainLoop *) data;
  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_EOS:
      g_print ("End of stream\n");
      g_main_loop_quit (loop);
      break;
    case GST_MESSAGE_ERROR:{
      gchar *debug;
      GError *error;
      gst_message_parse_error (msg, &error, &debug);
      g_printerr ("ERROR from element %s: %s\n",
          GST_OBJECT_NAME (msg->src), error->message);
      if (debug)
        g_printerr ("Error details: %s\n", debug);
      g_free (debug);
      g_error_free (error);
      g_main_loop_quit (loop);
      break;
    }
    default:
      break;
  }
  return TRUE;
}

int
main (int argc, char *argv[])
{
  GMainLoop *loop = NULL;
  GstElement *pipeline = NULL, *source = NULL, *h264parser = NULL,
      *decoder = NULL, *sink = NULL, *pgie = NULL, *nvvidconv = NULL,
      *nvosd = NULL, *tracker = NULL;
  GstBus *bus = NULL;
  guint bus_watch_id;
  gulong osd_probe_id = 0;
  GstPad *osd_sink_pad = NULL;

  /* Check input arguments */
  if (argc != 2) {
    g_printerr ("Usage: %s <H264 filename>\n", argv[0]);
    return -1;
  }

  /* Standard GStreamer initialization */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

  /* Create gstreamer elements */
  /* Create Pipeline element that will form a connection of other elements */
  pipeline = gst_pipeline_new ("dstest1-pipeline");

  /* Source element for reading from the file */
  source = gst_element_factory_make ("filesrc", "file-source");

  /* Since the data format in the input file is elementary h264 stream,
   * we need a h264parser */
  h264parser = gst_element_factory_make ("h264parse", "h264-parser");

  /* Use nvdec_h264 for hardware accelerated decode on GPU */
  decoder = gst_element_factory_make ("nvdec_h264", "nvh264-decoder");

  /* Use nvinfer to run inferencing on decoder's output,
   * behaviour of inferencing is set through config file */
  pgie = gst_element_factory_make ("nvinfer", "primary-nvinference-engine");

  /* Use nvtracker to tracker the result*/
  tracker = gst_element_factory_make ("nvtracker", "nvidia-tracker");

  /* Use convertor to convert from NV12 to RGBA as required by nvosd */
  nvvidconv = gst_element_factory_make ("nvvidconv", "nvvideo-converter");

  /* Create OSD to draw on the converted RGBA buffer */
  nvosd = gst_element_factory_make ("nvosd", "nv-onscreendisplay");

  /* Finally render the osd output */
  sink = gst_element_factory_make ("nveglglessink", "nvvideo-renderer");

  if (!pipeline || !source || !h264parser || !decoder || !pgie
      || !nvvidconv || !nvosd || !sink) {
    g_printerr ("One element could not be created. Exiting.\n");
    return -1;
  }

  /* we set the input filename to the source element */
  g_object_set (G_OBJECT (source), "location", argv[1], NULL);

  /* Set all the necessary properties of the nvinfer element,
   * the necessary ones are : */
  g_object_set (G_OBJECT (pgie),
      "config-file-path", "dstest1_pgie_config.txt", NULL);

  /* we set the input tracking configuration into tracking element */
  g_object_set (G_OBJECT (tracker), "tracker-width", 640, "tracker-height", 368, 
  "tracker-algorithm", 1, "iou-threshold", 0.9, NULL);

  /* we set the osd properties here */
  g_object_set (G_OBJECT (nvosd), "font-size", 15, NULL);

  /* we add a message handler */
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  /* Set up the pipeline */
  /* we add all elements into the pipeline */
  gst_bin_add_many (GST_BIN (pipeline),
      source, h264parser, decoder, pgie, tracker,
      nvvidconv, nvosd, sink, NULL);

  /* we link the elements together */
  /* file-source -> h264-parser -> nvh264-decoder ->
   * nvinfer -> nvtracker -> nvvidconv -> nvosd -> video-renderer */
  if (!gst_element_link_many (source, h264parser, decoder, pgie, tracker,
      nvvidconv, nvosd, sink, NULL)) {
    g_printerr ("Elements could not be linked. Exiting.\n");
    return -1;
  }

  /* Lets add probe to get informed of the meta data generated, we add probe to
   * the sink pad of the osd element, since by that time, the buffer would have
   * had got all the metadata. */
  osd_sink_pad = gst_element_get_static_pad (nvosd, "sink");
  if (!osd_sink_pad)
    g_print ("Unable to get sink pad\n");
  else
    osd_probe_id = gst_pad_add_probe (osd_sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
        osd_sink_pad_buffer_probe, NULL, NULL);

  /* Set the pipeline to "playing" state */
  g_print ("Now playing: %s\n", argv[1]);
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  /* Wait till pipeline encounters an error or EOS */
  g_print ("Running...\n");
  g_main_loop_run (loop);

  /* Out of the main loop, clean up nicely */
  g_print ("Returned, stopping playback\n");
  gst_element_set_state (pipeline, GST_STATE_NULL);
  g_print ("Deleting pipeline\n");
  gst_object_unref (GST_OBJECT (pipeline));
  g_source_remove (bus_watch_id);
  g_main_loop_unref (loop);
  return 0;


}

Can you try to change
“osd_sink_pad = gst_element_get_static_pad (nvosd, “sink”);”
to
osd_sink_pad = gst_element_get_static_pad (nvosd, “src”);

Or change to
osd_sink_pad = gst_element_get_static_pad (decoder, “sink”);

Hi Chris,

I tried. Both suggestions don’t work in visualize the line. I guess the problem is NvOSD doesn’t read the NvDsLineMeta in my code. May I know the proper way to assign information into NvDsLineMeta.

/*
 * Copyright (c) 2018 NVIDIA Corporation.  All rights reserved.
 *
 * NVIDIA Corporation and its licensors retain all intellectual property
 * and proprietary rights in and to this software, related documentation
 * and any modifications thereto.  Any use, reproduction, disclosure or
 * distribution of this software and related documentation without an express
 * license agreement from NVIDIA Corporation is strictly prohibited.
 *
 */

#include <gst/gst.h>
#include <glib.h>

#include "gstnvdsmeta.h"

#define MAX_DISPLAY_LEN 64

#define PGIE_CLASS_ID_VEHICLE 0
#define PGIE_CLASS_ID_PERSON 2

gint frame_number = 0;
gchar pgie_classes_str[4][32] = { "Vehicle", "TwoWheeler", "Person",
  "Roadsign"
};

static void generate_line_meta(gpointer data)
{ guint l_index, num_lines;
  
  NvDsLineMeta *meta = (NvDsLineMeta *) data;
  meta->num_lines = 1.0;
  meta->batch_id = 1.0;
  num_lines = meta->num_lines;
  
  NvOSD_LineParams *line_param = (NvOSD_LineParams *) g_malloc0 (sizeof (NvOSD_LineParams));
  meta->line_params = g_malloc0 (sizeof (NvOSD_LineParams));
  line_param = g_malloc0 (sizeof (NvOSD_LineParams)); 
  line_param->x1 = 100;
  line_param->y1 = 100;
  line_param->x2 = 400;
  line_param->y2 = 400;
  line_param->line_width = 10;
  line_param->line_color.red = 1.0;
  line_param->line_color.green = 0.0;
  line_param->line_color.blue = 0.0;
  line_param->line_color.alpha = 1.0;

  meta->line_params= line_param;

  //g_print ("Test %d\n", meta->line_params[0].x1);
}

/* osd_sink_pad_buffer_probe  will extract metadata received on OSD sink pad
 * and update params for drawing rectangle, object information etc. */

static GstPadProbeReturn
osd_sink_pad_buffer_probe (GstPad * pad, GstPadProbeInfo * info,
    gpointer u_data)
{

  GstMeta *gst_meta = NULL;
  NvDsMeta *nvdsmeta = NULL;
  gpointer state = NULL;
  static GQuark _nvdsmeta_quark = 0;    
  GstBuffer *buf = (GstBuffer *) info->data;   //Put all the data from the probe to GstBuffer buf
  NvDsFrameMeta *frame_meta = NULL;
  guint num_rects = 0, rect_index = 0, l_index = 0;
  NvDsObjectParams *obj_meta = NULL;
  guint i = 0;
  NvOSD_TextParams *txt_params = NULL;
  guint vehicle_count = 0;
  guint person_count = 0;
  gboolean is_first_rect = TRUE;

  if (!_nvdsmeta_quark)
    _nvdsmeta_quark = g_quark_from_static_string (NVDS_META_STRING);   //NVDS_META_STRING = nvdsmeta, get a quark from nvdsmeta, if NULL, create a new quark to nvdsmeta.

  while ((gst_meta = gst_buffer_iterate_meta (buf, &state))) {         //&state = NULL, Get the the gst_meta from the current buffer. Iterate the buffer to get NvDsMeta.
    if (gst_meta_api_type_has_tag (gst_meta->info->api, _nvdsmeta_quark)) {    //To find the gst_meta with quark tag (nvdsmeta), so that it return TRUE for nvdsmeta.

      nvdsmeta = (NvDsMeta *) gst_meta;                                  

      /* We are interested only in intercepting Meta of type
       * "NVDS_META_FRAME_INFO" as they are from our infer elements. */
      if (nvdsmeta->meta_type == NVDS_META_FRAME_INFO) {          //There are still alot of information from NvDsMeta nvdsmeta, set meta_type to NVDS_META_FRAME_INFO only
        frame_meta = (NvDsFrameMeta *) nvdsmeta->meta_data;       //Set nvdsmeta->(gpointer)meta_data to frame_meta.
        if (frame_meta == NULL) {
          g_print ("NvDS Meta contained NULL meta \n");
          return GST_PAD_PROBE_OK;
        }

        /* We reset the num_strings here as we plan to iterate through the
         *  the detected objects and form our own strings.
         *  The pipeline generated strings shall be discarded.
         */
        frame_meta->num_strings = 0;

        num_rects = frame_meta->num_rects;
        is_first_rect = TRUE;

        /* This means we have num_rects in frame_meta->obj_params,
         * now lets iterate through them */

        for (rect_index = 0; rect_index < num_rects; rect_index++) {
          /* Now using above information we need to form a text that should
           * be displayed on top of the bounding box, so lets form it here. */

          obj_meta = (NvDsObjectParams *) & frame_meta->obj_params[rect_index];

          txt_params = &(obj_meta->text_params);
          if (txt_params->display_text)
            g_free (txt_params->display_text);

          txt_params->display_text = g_malloc0 (MAX_DISPLAY_LEN);

          g_snprintf (txt_params->display_text, MAX_DISPLAY_LEN, "%s %d",
              pgie_classes_str[obj_meta->class_id], obj_meta->tracking_id );

          if (obj_meta->class_id == PGIE_CLASS_ID_VEHICLE)
            vehicle_count++;
          if (obj_meta->class_id == PGIE_CLASS_ID_PERSON)
            person_count++;

          /* Now set the offsets where the string should appear */
          txt_params->x_offset = obj_meta->rect_params.left;
          txt_params->y_offset = obj_meta->rect_params.top - 25;

          /* Font , font-color and font-size */
          txt_params->font_params.font_name = "Arial";
          txt_params->font_params.font_size = 10;
          txt_params->font_params.font_color.red = 1.0;
          txt_params->font_params.font_color.green = 1.0;
          txt_params->font_params.font_color.blue = 1.0;
          txt_params->font_params.font_color.alpha = 1.0;

          /* Text background color */
          txt_params->set_bg_clr = 1;
          txt_params->text_bg_clr.red = 0.0;
          txt_params->text_bg_clr.green = 0.0;
          txt_params->text_bg_clr.blue = 0.0;
          txt_params->text_bg_clr.alpha = 1.0;

          frame_meta->num_strings++;

          NvDsMeta *gst_line_meta = NULL;
          NvDsLineMeta *line_meta = (NvDsLineMeta *) g_malloc0 (sizeof (NvDsEventMsgMeta));
          generate_line_meta (line_meta);
          //g_print ("line = %d\n", line_meta->line_params->x1);
          gst_line_meta = gst_buffer_add_nvds_meta (buf, (void*)line_meta, (GDestroyNotify)nvds_free_line_info);
          if (gst_line_meta) {
            gst_line_meta->meta_type = NVDS_META_LINE_INFO;

          } else {
            g_print ("Error in attaching event meta to buffer\n");
          }
          
        }
      }
    }
  }
  /*
  g_print ("Frame Number = %d Number of objects = %d "
      "Vehicle Count = %d Person Count = %d  Line_Present = %d\n",
      frame_number, num_rects, vehicle_count, person_count, obj_meta->lines_present);*/
  frame_number++;

  return GST_PAD_PROBE_OK;
}

static gboolean
bus_call (GstBus * bus, GstMessage * msg, gpointer data)
{
  GMainLoop *loop = (GMainLoop *) data;
  switch (GST_MESSAGE_TYPE (msg)) {
    case GST_MESSAGE_EOS:
      g_print ("End of stream\n");
      g_main_loop_quit (loop);
      break;
    case GST_MESSAGE_ERROR:{
      gchar *debug;
      GError *error;
      gst_message_parse_error (msg, &error, &debug);
      g_printerr ("ERROR from element %s: %s\n",
          GST_OBJECT_NAME (msg->src), error->message);
      if (debug)
        g_printerr ("Error details: %s\n", debug);
      g_free (debug);
      g_error_free (error);
      g_main_loop_quit (loop);
      break;
    }
    default:
      break;
  }
  return TRUE;
}

int
main (int argc, char *argv[])
{
  GMainLoop *loop = NULL;
  GstElement *pipeline = NULL, *source = NULL, *h264parser = NULL,
      *decoder = NULL, *sink = NULL, *pgie = NULL, *nvvidconv = NULL,
      *nvosd = NULL, *tracker = NULL;
  GstBus *bus = NULL;
  guint bus_watch_id;
  gulong osd_probe_id = 0;
  GstPad *osd_sink_pad = NULL;

  /* Check input arguments */
  if (argc != 2) {
    g_printerr ("Usage: %s <H264 filename>\n", argv[0]);
    return -1;
  }

  /* Standard GStreamer initialization */
  gst_init (&argc, &argv);
  loop = g_main_loop_new (NULL, FALSE);

  /* Create gstreamer elements */
  /* Create Pipeline element that will form a connection of other elements */
  pipeline = gst_pipeline_new ("dstest1-pipeline");

  /* Source element for reading from the file */
  source = gst_element_factory_make ("filesrc", "file-source");

  /* Since the data format in the input file is elementary h264 stream,
   * we need a h264parser */
  h264parser = gst_element_factory_make ("h264parse", "h264-parser");

  /* Use nvdec_h264 for hardware accelerated decode on GPU */
  decoder = gst_element_factory_make ("nvdec_h264", "nvh264-decoder");

  /* Use nvinfer to run inferencing on decoder's output,
   * behaviour of inferencing is set through config file */
  pgie = gst_element_factory_make ("nvinfer", "primary-nvinference-engine");

  /* Use nvtracker to tracker the result*/
  tracker = gst_element_factory_make ("nvtracker", "nvidia-tracker");

  /* Use convertor to convert from NV12 to RGBA as required by nvosd */
  nvvidconv = gst_element_factory_make ("nvvidconv", "nvvideo-converter");

  /* Create OSD to draw on the converted RGBA buffer */
  nvosd = gst_element_factory_make ("nvosd", "nv-onscreendisplay");

  /* Finally render the osd output */
  sink = gst_element_factory_make ("nveglglessink", "nvvideo-renderer");

  if (!pipeline || !source || !h264parser || !decoder || !pgie
      || !nvvidconv || !nvosd || !sink) {
    g_printerr ("One element could not be created. Exiting.\n");
    return -1;
  }

  /* we set the input filename to the source element */
  g_object_set (G_OBJECT (source), "location", argv[1], NULL);

  /* Set all the necessary properties of the nvinfer element,
   * the necessary ones are : */
  g_object_set (G_OBJECT (pgie),
      "config-file-path", "dstest1_pgie_config.txt", NULL);

  /* we set the input tracking configuration into tracking element */
  g_object_set (G_OBJECT (tracker), "tracker-width", 640, "tracker-height", 368, 
  "tracker-algorithm", 1, "iou-threshold", 0.9, NULL);

  /* we set the osd properties here */
  g_object_set (G_OBJECT (nvosd), "font-size", 15, NULL);

  /* we add a message handler */
  bus = gst_pipeline_get_bus (GST_PIPELINE (pipeline));
  bus_watch_id = gst_bus_add_watch (bus, bus_call, loop);
  gst_object_unref (bus);

  /* Set up the pipeline */
  /* we add all elements into the pipeline */
  gst_bin_add_many (GST_BIN (pipeline),
      source, h264parser, decoder, pgie, tracker,
      nvvidconv, nvosd, sink, NULL);

  /* we link the elements together */
  /* file-source -> h264-parser -> nvh264-decoder ->
   * nvinfer -> nvtracker -> nvvidconv -> nvosd -> video-renderer */
  if (!gst_element_link_many (source, h264parser, decoder, pgie, tracker,
      nvvidconv, nvosd, sink, NULL)) {
    g_printerr ("Elements could not be linked. Exiting.\n");
    return -1;
  }

  /* Lets add probe to get informed of the meta data generated, we add probe to
   * the sink pad of the osd element, since by that time, the buffer would have
   * had got all the metadata. */
  osd_sink_pad = gst_element_get_static_pad (nvosd, "sink");
  if (!osd_sink_pad)
    g_print ("Unable to get sink pad\n");
  else
    osd_probe_id = gst_pad_add_probe (osd_sink_pad, GST_PAD_PROBE_TYPE_BUFFER,
        osd_sink_pad_buffer_probe, NULL, NULL);

  /* Set the pipeline to "playing" state */
  g_print ("Now playing: %s\n", argv[1]);
  gst_element_set_state (pipeline, GST_STATE_PLAYING);

  /* Wait till pipeline encounters an error or EOS */
  g_print ("Running...\n");
  g_main_loop_run (loop);

  /* Out of the main loop, clean up nicely */
  g_print ("Returned, stopping playback\n");
  gst_element_set_state (pipeline, GST_STATE_NULL);
  g_print ("Deleting pipeline\n");
  gst_object_unref (GST_OBJECT (pipeline));
  g_source_remove (bus_watch_id);
  g_main_loop_unref (loop);
  return 0;

}

Capture.PNG

I have checked libgstnvosd reads NVDS_META_LINE_INFO metadata and draw the line by cairo lib (by CPU).

Hello Chris,

Thank your instant reply. I guess there maybe some mistakes between line 148 to 158 while I am assigning the line information to NvDsLineMeta. I am figuring it.

Hi Chris,

I found the problem and solved it. Thank you for your help.

Regards,
Nero

Hi Nero,

May I know what is the error with the above program. How do you resolved it?
I couldn’ able to find any struct named NvDsLineMeta & NvDsLineparamas are coming with deepstream headers Or is that manual configured one.

Hi,
I have the same problem and I saw in this topic that you solved it.
Could you please share what you have found ?
Thank you !