Example Pipelines - Example Pipelines - 6.3 English - XD056

Vitis Video Analytics SDK (VVAS) 6.3 User Guide (XD056)

Document_ID
XD056
Release_Date
2026-09-24
Version
6.3 English
  • The following pipeline converts NV12 to RGB and performs scaling from 1920x1080 to 640x480.

gst-launch-1.0 -v \
videotestsrc num-buffers=10 ! video/x-raw,format=NV12,width=1920,height=1080 \
! vvas_xmulticrop xclbin-location=/run/media/mmcblk0p1/x_plus_ml.xclbin \
! video/x-raw,format=RGB,width=640,height=480 ! filesink location=out_480p.rgb
  • The following pipeline performs pre-processing along with color space conversion and scaling on output buffers.

gst-launch-1.0 -v \
videotestsrc num-buffers=10 ! video/x-raw,format=NV12,width=1920,height=1080 \
! vvas_xmulticrop ppe-on-main-buffer=true alpha-r=124 alpha-g=116 alpha-b=104 beta-r=0.547 beta-g=0.56 beta-b=0.557 xclbin-location=/run/media/mmcblk0p1/x_plus_ml.xclbin \
! video/x-raw,format=RGB,width=640,height=480 ! filesink location=out_480p.rgb
  • The pipeline performs static cropping at (x,y) = (100,80) and (width,height)= (1280,720); this cropped buffers gets scaled to 640x480 and converted to RGB.

gst-launch-1.0 -v \
videotestsrc num-buffers=10 ! video/x-raw,format=NV12,width=1920,height=1080 \
! vvas_xmulticrop s-crop-x=100 s-crop-y=80 s-crop-width=1280 s-crop-height=720 xclbin-location=/run/media/mmcblk0p1/x_plus_ml.xclbin \
! video/x-raw,format=RGB,width=640,height=480 ! filesink location=out_480p.rgb
  • The following code shows how to add GstVideoRegionOfInterestMeta for dynamic cropping.

GstVideoRegionOfInterestMeta *meta;
meta = gst_buffer_add_video_region_of_interest_meta (buffer, "roi-crop-meta", 0, 0, 0, 0);
if (meta) {
  meta->id = id;
  meta->parent_id = p_id;
  meta->x =  x;
  meta->y =  y;
  meta->w = w;
  meta->h = h;
  printf("meta: x:%u y:%u, w:%u h:%u", meta->x, meta->y, meta->w, meta->h);
}
  • The following code shows how to read GstVideoRegionOfInterestMeta and how to extract a dynamically cropped buffer/object.

read_crop_meta (GstBuffer *buf) {
  gpointer state = NULL;
  GstMeta *_meta;
  while ((_meta = gst_buffer_iterate_meta_filtered (buf, &state,
              GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE))) {
    GstStructure *s = NULL;
    GstVideoRegionOfInterestMeta *roi_meta =
                          (GstVideoRegionOfInterestMeta  *) _meta;
    if (g_strcmp0("roi-crop-meta", g_quark_to_string (roi_meta->roi_type))) {
      //This is not the metadata we are looking for
      continue;
    }
    //Got the ROI crop metadata, prepare output buffer
    //Extract dynamically cropped buffer from this meta
    s = gst_video_region_of_interest_meta_get_param (roi_meta, "roi-buffer");
    if (s) {
      GstBuffer *sub_buffer = NULL;
      gst_structure_get (s, "sub-buffer", GST_TYPE_BUFFER, &sub_buffer, NULL);
      if (sub_buffer) {
        //use sub_buffer and unref it
        dump_dynamically_cropped_buffer (sub_buffer);
      } else {
        printf("couldn't get sub buffer");
      }
    } else {
      printf("couldn't get expected struct");
    }
  }
  return TRUE;
}
  • The following code shows how to read/dump dynamically cropped buffers.

static gboolean
dump_dynamically_cropped_buffer (GstBuffer *sub_buffer)
{
  //Read GstVideoMeta from the buffer, dump the buffer to file
  GstVideoMeta *vmeta = NULL;
  FILE *fp;
  gchar name[256] = { 0 };
  guint i, j, n_planes;
  GstVideoFrame out_frame = { 0 };
  GstVideoFrame new_frame = { 0 };
  GstVideoInfo *vinfo;
  GstBuffer *new_outbuf;
  guint8 *data_ptr, *out_ptr;
  guint w, h;
  gint src_stride;
  const GstVideoFormatInfo *finfo;
  gint comp[GST_VIDEO_MAX_COMPONENTS];
  const GstVideoInfo *sinfo;

  if (!sub_buffer) {
    return FALSE;
  }

  vmeta = gst_buffer_get_video_meta (sub_buffer);
  if (!vmeta) {
    printf ("couldn't get video meta\n");
    return FALSE;
  }

  sprintf (name, "dynbuf_%ux%u_%s.yuv", vmeta->width, vmeta->height,
      gst_video_format_to_string (vmeta->format));
  fp = fopen (name, "wb");
  if (!fp) {
    return FALSE;
  }

  vinfo = gst_video_info_new ();
  gst_video_info_set_format (vinfo, vmeta->format, vmeta->width, vmeta->height);

  new_outbuf = gst_buffer_new_and_alloc (GST_VIDEO_INFO_SIZE (vinfo));
  if (!new_outbuf) {
    printf ("couldn't allocate buffer\n");
    gst_video_info_free (vinfo);
    fclose (fp);
    return FALSE;
  }

  gst_video_frame_map (&out_frame, vinfo, sub_buffer, GST_MAP_READ);
  gst_video_frame_map (&new_frame, vinfo, new_outbuf,
      GST_MAP_READ | GST_MAP_WRITE);

  sinfo = &out_frame.info;
  finfo = sinfo->finfo;
  n_planes = finfo->n_planes;

  for (i = 0; i < n_planes; i++) {
    gst_video_format_info_component (finfo, i, comp);
    data_ptr = out_frame.data[i];
    out_ptr = new_frame.data[i];

    w = GST_VIDEO_FRAME_COMP_WIDTH (&out_frame, comp[0])
        * GST_VIDEO_FRAME_COMP_PSTRIDE (&out_frame, comp[0]);

    h = GST_VIDEO_FRAME_COMP_HEIGHT (&out_frame, comp[0]);
    src_stride = GST_VIDEO_INFO_PLANE_STRIDE (sinfo, i);
    for (j = 0; j < h; j++) {
      memcpy (out_ptr, data_ptr, w);
      data_ptr += src_stride;
      out_ptr += w;
    }
    fwrite (new_frame.data[i], 1, w * h, fp);
  }

  gst_video_frame_unmap (&out_frame);
  gst_video_frame_unmap (&new_frame);
  gst_video_info_free (vinfo);
  gst_buffer_unref (new_outbuf);
  fclose (fp);
  gst_buffer_unref (sub_buffer);
  return TRUE;
}