diff --git a/Makefile b/Makefile
index 27fced6..687a77b 100644
--- a/Makefile
+++ b/Makefile
@@ -22,7 +22,7 @@
 #enable this flag to use optimized dsexample plugin
 #it can also be exported from command line
 USE_OPTIMIZED_DSEXAMPLE?=0
-CUDA_VER?=
+CUDA_VER?=10.2
 ifeq ($(CUDA_VER),)
   $(error "CUDA_VER is not set")
 endif
@@ -46,15 +46,16 @@ DEP_FILES-=$(DEP)
 
 CFLAGS+= -fPIC -DDS_VERSION=\"5.0.0\" \
 	 -I /usr/local/cuda-$(CUDA_VER)/include \
-	 -I ../../includes
+	 -I ../../includes \
+	 -I /opt/nvidia/vpi1/include/vpi/
 
 GST_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/gst-plugins/
 LIB_INSTALL_DIR?=/opt/nvidia/deepstream/deepstream-$(NVDS_VERSION)/lib/
 
 LIBS := -shared -Wl,-no-undefined \
 	-L dsexample_lib -ldsexample \
-	-L/usr/local/cuda-$(CUDA_VER)/lib64/ -lcudart -ldl \
-	-lnppc -lnppig -lnpps -lnppicc -lnppidei \
+	-L/usr/local/cuda-$(CUDA_VER)/lib64/ -lcudart -lcuda -ldl \
+	-L/opt/nvidia/vpi1/lib64/ -lnvvpi \
 	-L$(LIB_INSTALL_DIR) -lnvdsgst_helper -lnvdsgst_meta -lnvds_meta -lnvbufsurface -lnvbufsurftransform\
 	-Wl,-rpath,$(LIB_INSTALL_DIR)
 
diff --git a/dsexample_lib/dsexample_lib.c b/dsexample_lib/dsexample_lib.c
index 086ba74..82b1506 100644
--- a/dsexample_lib/dsexample_lib.c
+++ b/dsexample_lib/dsexample_lib.c
@@ -51,38 +51,22 @@ DsExampleProcess (DsExampleCtx * ctx, unsigned char *data)
     }
     // Fill output structure using processed output
     // Here, we fake some detected objects and labels
-    if (ctx->initParams.fullFrame)
+    out->numObjects = 2;
+    out->object[0] = (DsExampleObject)
     {
-        out->numObjects = 2;
-        out->object[0] = (DsExampleObject)
-        {
+        (float)(ctx->initParams.processingWidth) / 8,
+            (float)(ctx->initParams.processingHeight) / 8,
             (float)(ctx->initParams.processingWidth) / 8,
-                (float)(ctx->initParams.processingHeight) / 8,
-                (float)(ctx->initParams.processingWidth) / 8,
-                (float)(ctx->initParams.processingHeight) / 8, "Obj0"
-        };
+            (float)(ctx->initParams.processingHeight) / 8, "Obj0"
+    };
 
-        out->object[1] = (DsExampleObject)
-        {
-            (float)(ctx->initParams.processingWidth) / 2,
-                (float)(ctx->initParams.processingHeight) / 2,
-                (float)(ctx->initParams.processingWidth) / 8,
-                (float)(ctx->initParams.processingHeight) / 8, "Obj1"
-        };
-    }
-    else
+    out->object[1] = (DsExampleObject)
     {
-        out->numObjects = 1;
-        out->object[0] = (DsExampleObject)
-        {
+        (float)(ctx->initParams.processingWidth) / 2,
+            (float)(ctx->initParams.processingHeight) / 2,
             (float)(ctx->initParams.processingWidth) / 8,
-                (float)(ctx->initParams.processingHeight) / 8,
-                (float)(ctx->initParams.processingWidth) / 8,
-                (float)(ctx->initParams.processingHeight) / 8, ""
-        };
-        // Set the object label
-        snprintf (out->object[0].label, 64, "Obj_label");
-    }
+            (float)(ctx->initParams.processingHeight) / 8, "Obj1"
+    };
 
     return out;
 }
diff --git a/dsexample_lib/dsexample_lib.h b/dsexample_lib/dsexample_lib.h
index 5920b39..5d365cf 100644
--- a/dsexample_lib/dsexample_lib.h
+++ b/dsexample_lib/dsexample_lib.h
@@ -37,8 +37,6 @@ typedef struct
   int processingWidth;
   // height at which frame/object will be scaled
   int processingHeight;
-  // Flag to indicate whether operating on crops of full frame
-  int fullFrame;
 } DsExampleInitParams;
 
 // Detected/Labelled object structure, stores bounding box info along with label
diff --git a/gstdsexample.cpp b/gstdsexample.cpp
index 5bf6c89..24adb5b 100644
--- a/gstdsexample.cpp
+++ b/gstdsexample.cpp
@@ -20,14 +20,24 @@
  * DEALINGS IN THE SOFTWARE.
  */
 
-#include <string.h>
 #include <string>
 #include <sstream>
 #include <iostream>
 #include <ostream>
 #include <fstream>
-#include "gstdsexample.h"
 #include <sys/time.h>
+
+#include <algorithm>
+#include <vpi/Context.h>
+#include <vpi/Image.h>
+#include <vpi/Status.h>
+#include <vpi/algo/ConvertImageFormat.h>
+#include <vpi/algo/PerspectiveWarp.h>
+#include <vpi/CUDAInterop.h>
+
+#include "cudaEGL.h"
+#include "gstdsexample.h"
+
 GST_DEBUG_CATEGORY_STATIC (gst_dsexample_debug);
 #define GST_CAT_DEFAULT gst_dsexample_debug
 #define USE_EGLIMAGE 1
@@ -42,8 +52,6 @@ enum
   PROP_UNIQUE_ID,
   PROP_PROCESSING_WIDTH,
   PROP_PROCESSING_HEIGHT,
-  PROP_PROCESS_FULL_FRAME,
-  PROP_BLUR_OBJECTS,
   PROP_GPU_DEVICE_ID
 };
 
@@ -68,8 +76,6 @@ enum
 #define DEFAULT_UNIQUE_ID 15
 #define DEFAULT_PROCESSING_WIDTH 640
 #define DEFAULT_PROCESSING_HEIGHT 480
-#define DEFAULT_PROCESS_FULL_FRAME TRUE
-#define DEFAULT_BLUR_OBJECTS FALSE
 #define DEFAULT_GPU_ID 0
 
 #define RGB_BYTES_PER_PIXEL 3
@@ -77,17 +83,6 @@ enum
 #define Y_BYTES_PER_PIXEL 1
 #define UV_BYTES_PER_PIXEL 2
 
-#define MIN_INPUT_OBJECT_WIDTH 16
-#define MIN_INPUT_OBJECT_HEIGHT 16
-
-#define CHECK_NPP_STATUS(npp_status,error_str) do { \
-  if ((npp_status) != NPP_SUCCESS) { \
-    g_print ("Error: %s in %s at line %d: NPP Error %d\n", \
-        error_str, __FILE__, __LINE__, npp_status); \
-    goto error; \
-  } \
-} while (0)
-
 #define CHECK_CUDA_STATUS(cuda_status,error_str) do { \
   if ((cuda_status) != cudaSuccess) { \
     g_print ("Error: %s in %s at line %d (%s)\n", \
@@ -96,6 +91,18 @@ enum
   } \
 } while (0)
 
+#define CHECK_VPI_STATUS(STMT) do {                        \
+  VPIStatus status = (STMT);                               \
+  if (status != VPI_SUCCESS)                               \
+  {                                                        \
+    char buffer[VPI_MAX_STATUS_MESSAGE_LENGTH];            \
+    vpiGetLastStatusMessage(buffer, sizeof(buffer));       \
+    g_print ("Error: %s in %s at line %d (%s)\n",          \
+    vpiStatusGetName(status), __FILE__, __LINE__, buffer); \
+    goto error;                                            \
+  }                                                        \
+} while (0);
+
 /* By default NVIDIA Hardware allocated memory flows through the pipeline. We
  * will be processing on this type of memory only. */
 #define GST_CAPS_FEATURE_MEMORY_NVMM "memory:NVMM"
@@ -132,12 +139,6 @@ static gboolean gst_dsexample_stop (GstBaseTransform * btrans);
 static GstFlowReturn gst_dsexample_transform_ip (GstBaseTransform *
     btrans, GstBuffer * inbuf);
 
-static void
-attach_metadata_full_frame (GstDsExample * dsexample, NvDsFrameMeta *frame_meta,
-    gdouble scale_ratio, DsExampleOutput * output, guint batch_id);
-static void attach_metadata_object (GstDsExample * dsexample,
-    NvDsObjectMeta * obj_meta, DsExampleOutput * output);
-
 /* Install properties, set sink and src pad capabilities, override the required
  * functions of the base class, These are common to all instances of the
  * element.
@@ -189,20 +190,6 @@ gst_dsexample_class_init (GstDsExampleClass * klass)
           1, G_MAXINT, DEFAULT_PROCESSING_HEIGHT, (GParamFlags)
           (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
 
-  g_object_class_install_property (gobject_class, PROP_PROCESS_FULL_FRAME,
-      g_param_spec_boolean ("full-frame",
-          "Full frame",
-          "Enable to process full frame or disable to process objects detected"
-          "by primary detector", DEFAULT_PROCESS_FULL_FRAME, (GParamFlags)
-          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
-
-  g_object_class_install_property (gobject_class, PROP_BLUR_OBJECTS,
-      g_param_spec_boolean ("blur-objects",
-          "Blur Objects",
-          "Enable to blur the objects detected in full-frame=0 mode"
-          "by primary detector", DEFAULT_BLUR_OBJECTS, (GParamFlags)
-          (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
-
   g_object_class_install_property (gobject_class, PROP_GPU_DEVICE_ID,
       g_param_spec_uint ("gpu-id",
           "Set GPU Device ID",
@@ -211,6 +198,7 @@ gst_dsexample_class_init (GstDsExampleClass * klass)
           GParamFlags
           (G_PARAM_READWRITE |
               G_PARAM_STATIC_STRINGS | GST_PARAM_MUTABLE_READY)));
+
   /* Set sink and src pad capabilities */
   gst_element_class_add_pad_template (gstelement_class,
       gst_static_pad_template_get (&gst_dsexample_src_template));
@@ -242,8 +230,6 @@ gst_dsexample_init (GstDsExample * dsexample)
   dsexample->unique_id = DEFAULT_UNIQUE_ID;
   dsexample->processing_width = DEFAULT_PROCESSING_WIDTH;
   dsexample->processing_height = DEFAULT_PROCESSING_HEIGHT;
-  dsexample->process_full_frame = DEFAULT_PROCESS_FULL_FRAME;
-  dsexample->blur_objects = DEFAULT_BLUR_OBJECTS;
   dsexample->gpu_id = DEFAULT_GPU_ID;
   /* This quark is required to identify NvDsMeta when iterating through
    * the buffer metadatas */
@@ -268,12 +254,6 @@ gst_dsexample_set_property (GObject * object, guint prop_id,
     case PROP_PROCESSING_HEIGHT:
       dsexample->processing_height = g_value_get_int (value);
       break;
-    case PROP_PROCESS_FULL_FRAME:
-      dsexample->process_full_frame = g_value_get_boolean (value);
-      break;
-    case PROP_BLUR_OBJECTS:
-      dsexample->blur_objects = g_value_get_boolean (value);
-      break;
     case PROP_GPU_DEVICE_ID:
       dsexample->gpu_id = g_value_get_uint (value);
       break;
@@ -302,12 +282,6 @@ gst_dsexample_get_property (GObject * object, guint prop_id,
     case PROP_PROCESSING_HEIGHT:
       g_value_set_int (value, dsexample->processing_height);
       break;
-    case PROP_PROCESS_FULL_FRAME:
-      g_value_set_boolean (value, dsexample->process_full_frame);
-      break;
-    case PROP_BLUR_OBJECTS:
-      g_value_set_boolean (value, dsexample->blur_objects);
-      break;
     case PROP_GPU_DEVICE_ID:
       g_value_set_uint (value, dsexample->gpu_id);
       break;
@@ -326,9 +300,7 @@ gst_dsexample_start (GstBaseTransform * btrans)
   GstDsExample *dsexample = GST_DSEXAMPLE (btrans);
   NvBufSurfaceCreateParams create_params;
   DsExampleInitParams init_params =
-      { dsexample->processing_width, dsexample->processing_height,
-    dsexample->process_full_frame
-  };
+      { dsexample->processing_width, dsexample->processing_height};
 
   GstQuery *queryparams = NULL;
   guint batch_size = 1;
@@ -353,68 +325,18 @@ gst_dsexample_start (GstBaseTransform * btrans)
       dsexample->batch_size);
   gst_query_unref (queryparams);
 
-  if (dsexample->process_full_frame && dsexample->blur_objects) {
-    GST_ERROR ("Error: does not support blurring while processing full frame");
-    goto error;
-  }
-
-  CHECK_CUDA_STATUS (cudaStreamCreate (&dsexample->cuda_stream),
-      "Could not create cuda stream");
-
-  if (dsexample->inter_buf)
-    NvBufSurfaceDestroy (dsexample->inter_buf);
-  dsexample->inter_buf = NULL;
-
-  /* An intermediate buffer for NV12/RGBA to BGR conversion  will be
-   * required. Can be skipped if custom algorithm can work directly on NV12/RGBA. */
-  create_params.gpuId  = dsexample->gpu_id;
-  create_params.width  = dsexample->processing_width;
-  create_params.height = dsexample->processing_height;
-  create_params.size = 0;
-  create_params.colorFormat = NVBUF_COLOR_FORMAT_RGBA;
-  create_params.layout = NVBUF_LAYOUT_PITCH;
-#ifdef __aarch64__
-  create_params.memType = NVBUF_MEM_DEFAULT;
-#else
-  create_params.memType = NVBUF_MEM_CUDA_UNIFIED;
-#endif
-
-  if (NvBufSurfaceCreate (&dsexample->inter_buf, 1,
-          &create_params) != 0) {
-    GST_ERROR ("Error: Could not allocate internal buffer for dsexample");
-    goto error;
-  }
-
-  /* Create host memory for storing converted/scaled interleaved RGB data */
-  CHECK_CUDA_STATUS (cudaMallocHost (&dsexample->host_rgb_buf,
-          dsexample->processing_width * dsexample->processing_height *
-          RGB_BYTES_PER_PIXEL), "Could not allocate cuda host buffer");
-
-  GST_DEBUG_OBJECT (dsexample, "allocated cuda buffer %p \n",
-      dsexample->host_rgb_buf);
-
-  /* CV Mat containing interleaved RGB data. This call does not allocate memory.
-   * It uses host_rgb_buf as data. */
-  dsexample->cvmat =
-      new cv::Mat (dsexample->processing_height, dsexample->processing_width,
-      CV_8UC3, dsexample->host_rgb_buf,
-      dsexample->processing_width * RGB_BYTES_PER_PIXEL);
-
-  if (!dsexample->cvmat)
-    goto error;
-
-  GST_DEBUG_OBJECT (dsexample, "created CV Mat\n");
+  CHECK_VPI_STATUS(vpiStreamCreate(VPI_BACKEND_CUDA, &dsexample->vpi_stream));
+  CHECK_VPI_STATUS(vpiCreatePerspectiveWarp(VPI_BACKEND_CUDA, &dsexample->warp));
 
   return TRUE;
 error:
-  if (dsexample->host_rgb_buf) {
-    cudaFreeHost (dsexample->host_rgb_buf);
-    dsexample->host_rgb_buf = NULL;
+  if (dsexample->vpi_stream) {
+    vpiStreamDestroy (dsexample->vpi_stream);
+    dsexample->vpi_stream = NULL;
   }
-
-  if (dsexample->cuda_stream) {
-    cudaStreamDestroy (dsexample->cuda_stream);
-    dsexample->cuda_stream = NULL;
+  if (dsexample->warp) {
+    vpiPayloadDestroy(dsexample->warp);
+    dsexample->warp = NULL;
   }
   if (dsexample->dsexamplelib_ctx)
     DsExampleCtxDeinit (dsexample->dsexamplelib_ctx);
@@ -429,23 +351,13 @@ gst_dsexample_stop (GstBaseTransform * btrans)
 {
   GstDsExample *dsexample = GST_DSEXAMPLE (btrans);
 
-  if (dsexample->inter_buf)
-    NvBufSurfaceDestroy(dsexample->inter_buf);
-  dsexample->inter_buf = NULL;
-
-  if (dsexample->cuda_stream)
-    cudaStreamDestroy (dsexample->cuda_stream);
-  dsexample->cuda_stream = NULL;
-
-  delete dsexample->cvmat;
-  dsexample->cvmat = NULL;
-
-  if (dsexample->host_rgb_buf) {
-    cudaFreeHost (dsexample->host_rgb_buf);
-    dsexample->host_rgb_buf = NULL;
-  }
+  if (dsexample->vpi_stream)
+    vpiStreamDestroy (dsexample->vpi_stream);
+  dsexample->vpi_stream = NULL;
 
-  GST_DEBUG_OBJECT (dsexample, "deleted CV Mat \n");
+  if (dsexample->warp)
+    vpiPayloadDestroy(dsexample->warp);
+    dsexample->warp = NULL;
 
   /* Deinit the algorithm library */
   DsExampleCtxDeinit (dsexample->dsexamplelib_ctx);
@@ -467,191 +379,24 @@ gst_dsexample_set_caps (GstBaseTransform * btrans, GstCaps * incaps,
   /* Save the input video information, since this will be required later. */
   gst_video_info_from_caps (&dsexample->video_info, incaps);
 
-  if (dsexample->blur_objects && !dsexample->process_full_frame) {
-    /* requires RGBA format for blurring the objects in opencv */
-     if (dsexample->video_info.finfo->format != GST_VIDEO_FORMAT_RGBA) {
-      GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-          ("input format should be RGBA when using blur-objects property"), (NULL));
-      goto error;
-      }
-  }
-
   return TRUE;
-
-error:
-  return FALSE;
 }
 
-/**
- * Scale the entire frame to the processing resolution maintaining aspect ratio.
- * Or crop and scale objects to the processing resolution maintaining the aspect
- * ratio. Remove the padding required by hardware and convert from RGBA to RGB
- * using openCV. These steps can be skipped if the algorithm can work with
- * padded data and/or can work with RGBA.
- */
 static GstFlowReturn
-get_converted_mat (GstDsExample * dsexample, NvBufSurface *input_buf, gint idx,
-    NvOSD_RectParams * crop_rect_params, gdouble & ratio, gint input_width,
-    gint input_height)
+matrix_multiply (VPIPerspectiveTransform &r, const VPIPerspectiveTransform &a,
+                           const VPIPerspectiveTransform &b)
 {
-  NvBufSurfTransform_Error err;
-  NvBufSurfTransformConfigParams transform_config_params;
-  NvBufSurfTransformParams transform_params;
-  NvBufSurfTransformRect src_rect;
-  NvBufSurfTransformRect dst_rect;
-  NvBufSurface ip_surf;
-  cv::Mat in_mat;
-  ip_surf = *input_buf;
-
-  ip_surf.numFilled = ip_surf.batchSize = 1;
-  ip_surf.surfaceList = &(input_buf->surfaceList[idx]);
-
-  gint src_left = GST_ROUND_UP_2((unsigned int)crop_rect_params->left);
-  gint src_top = GST_ROUND_UP_2((unsigned int)crop_rect_params->top);
-  gint src_width = GST_ROUND_DOWN_2((unsigned int)crop_rect_params->width);
-  gint src_height = GST_ROUND_DOWN_2((unsigned int)crop_rect_params->height);
-
-  /* Maintain aspect ratio */
-  double hdest = dsexample->processing_width * src_height / (double) src_width;
-  double wdest = dsexample->processing_height * src_width / (double) src_height;
-  guint dest_width, dest_height;
-
-  if (hdest <= dsexample->processing_height) {
-    dest_width = dsexample->processing_width;
-    dest_height = hdest;
-  } else {
-    dest_width = wdest;
-    dest_height = dsexample->processing_height;
-  }
-
-  /* Configure transform session parameters for the transformation */
-  transform_config_params.compute_mode = NvBufSurfTransformCompute_Default;
-  transform_config_params.gpu_id = dsexample->gpu_id;
-  transform_config_params.cuda_stream = dsexample->cuda_stream;
-
-  /* Set the transform session parameters for the conversions executed in this
-   * thread. */
-  err = NvBufSurfTransformSetSessionParams (&transform_config_params);
-  if (err != NvBufSurfTransformError_Success) {
-    GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-        ("NvBufSurfTransformSetSessionParams failed with error %d", err), (NULL));
-    goto error;
-  }
-
-  /* Calculate scaling ratio while maintaining aspect ratio */
-  ratio = MIN (1.0 * dest_width/ src_width, 1.0 * dest_height / src_height);
-
-  if ((crop_rect_params->width == 0) || (crop_rect_params->height == 0)) {
-    GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-        ("%s:crop_rect_params dimensions are zero",__func__), (NULL));
-    goto error;
-  }
-
-#ifdef __aarch64__
-  if (ratio <= 1.0 / 16 || ratio >= 16.0) {
-    /* Currently cannot scale by ratio > 16 or < 1/16 for Jetson */
-    goto error;
-  }
-#endif
-  /* Set the transform ROIs for source and destination */
-  src_rect = {(guint)src_top, (guint)src_left, (guint)src_width, (guint)src_height};
-  dst_rect = {0, 0, (guint)dest_width, (guint)dest_height};
-
-  /* Set the transform parameters */
-  transform_params.src_rect = &src_rect;
-  transform_params.dst_rect = &dst_rect;
-  transform_params.transform_flag =
-    NVBUFSURF_TRANSFORM_FILTER | NVBUFSURF_TRANSFORM_CROP_SRC |
-      NVBUFSURF_TRANSFORM_CROP_DST;
-  transform_params.transform_filter = NvBufSurfTransformInter_Default;
-
-  /* Memset the memory */
-  NvBufSurfaceMemSet (dsexample->inter_buf, 0, 0, 0);
-
-  GST_DEBUG_OBJECT (dsexample, "Scaling and converting input buffer\n");
-
-  /* Transformation scaling+format conversion if any. */
-  err = NvBufSurfTransform (&ip_surf, dsexample->inter_buf, &transform_params);
-  if (err != NvBufSurfTransformError_Success) {
-    GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-        ("NvBufSurfTransform failed with error %d while converting buffer", err),
-        (NULL));
-    goto error;
-  }
-  /* Map the buffer so that it can be accessed by CPU */
-  if (NvBufSurfaceMap (dsexample->inter_buf, 0, 0, NVBUF_MAP_READ) != 0){
-    goto error;
-  }
-
-  /* Cache the mapped data for CPU access */
-  NvBufSurfaceSyncForCpu (dsexample->inter_buf, 0, 0);
-
-  /* Use openCV to remove padding and convert RGBA to BGR. Can be skipped if
-   * algorithm can handle padded RGBA data. */
-  in_mat =
-      cv::Mat (dsexample->processing_height, dsexample->processing_width,
-      CV_8UC4, dsexample->inter_buf->surfaceList[0].mappedAddr.addr[0],
-      dsexample->inter_buf->surfaceList[0].pitch);
-
-#if (CV_MAJOR_VERSION >= 4)
-  cv::cvtColor (in_mat, *dsexample->cvmat, cv::COLOR_RGBA2BGR);
-#else
-  cv::cvtColor (in_mat, *dsexample->cvmat, CV_RGBA2BGR);
-#endif
-
-  if (NvBufSurfaceUnMap (dsexample->inter_buf, 0, 0)){
-    goto error;
-  }
-
-#ifdef __aarch64__
-  /* To use the converted buffer in CUDA, create an EGLImage and then use
-   * CUDA-EGL interop APIs */
-  if (USE_EGLIMAGE) {
-    if (NvBufSurfaceMapEglImage (dsexample->inter_buf, 0) !=0 ) {
-      goto error;
+  for (int i = 0; i < 3; ++i)
+  {
+    for (int j = 0; j < 3; ++j)
+    {
+      r[i][j] = a[i][0] * b[0][j];
+      for (int k = 1; k < 3; ++k)
+      {
+        r[i][j] += a[i][k] * b[k][j];
+      }
     }
-
-    /* dsexample->inter_buf->surfaceList[0].mappedAddr.eglImage
-     * Use interop APIs cuGraphicsEGLRegisterImage and
-     * cuGraphicsResourceGetMappedEglFrame to access the buffer in CUDA */
-
-    /* Destroy the EGLImage */
-    NvBufSurfaceUnMapEglImage (dsexample->inter_buf, 0);
   }
-#endif
-
-  /* We will first convert only the Region of Interest (the entire frame or the
-   * object bounding box) to RGB and then scale the converted RGB frame to
-   * processing resolution. */
-  return GST_FLOW_OK;
-
-error:
-  return GST_FLOW_ERROR;
-}
-
-/*
- * Blur the detected objects when processing in object mode (full-frame=0)
- */
-static GstFlowReturn
-blur_objects (GstDsExample * dsexample, gint idx,
-    NvOSD_RectParams * crop_rect_params, cv::Mat in_mat)
-{
-  cv::Rect crop_rect;
-
-  if ((crop_rect_params->width == 0) || (crop_rect_params->height == 0)) {
-    GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-        ("%s:crop_rect_params dimensions are zero",__func__), (NULL));
-    return GST_FLOW_ERROR;
-  }
-
-/* rectangle for cropped objects */
-  crop_rect = cv::Rect (crop_rect_params->left, crop_rect_params->top,
-  crop_rect_params->width, crop_rect_params->height);
-
-/* apply gaussian blur to the detected objects */
-  GaussianBlur(in_mat(crop_rect), in_mat(crop_rect), cv::Size(15,15), 4);
-
-  return GST_FLOW_OK;
 }
 
 /**
@@ -661,17 +406,21 @@ static GstFlowReturn
 gst_dsexample_transform_ip (GstBaseTransform * btrans, GstBuffer * inbuf)
 {
   GstDsExample *dsexample = GST_DSEXAMPLE (btrans);
-  GstMapInfo in_map_info;
   GstFlowReturn flow_ret = GST_FLOW_ERROR;
-  gdouble scale_ratio = 1.0;
-  DsExampleOutput *output;
 
-  NvBufSurface *surface = NULL;
-  NvDsBatchMeta *batch_meta = NULL;
-  NvDsFrameMeta *frame_meta = NULL;
-  NvDsMetaList * l_frame = NULL;
+  GstMapInfo in_map_info;
+  NvBufSurface *surface;
+  CUeglFrame eglFrame;
+  CUgraphicsResource pResource;
+
+  float v1, v2;
   guint i = 0;
+  VPIImageData data;
+  VPIImage img;
+  VPIImage out;
 
+
+  /* get input buf */
   dsexample->frame_num++;
   CHECK_CUDA_STATUS (cudaSetDevice (dsexample->gpu_id),
       "Unable to set cuda device");
@@ -691,153 +440,83 @@ gst_dsexample_transform_ip (GstBaseTransform * btrans, GstBuffer * inbuf)
   if (CHECK_NVDS_MEMORY_AND_GPUID (dsexample, surface))
     goto error;
 
-  batch_meta = gst_buffer_get_nvds_batch_meta (inbuf);
-  if (batch_meta == nullptr) {
-    GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-        ("NvDsBatchMeta not found for input buffer."), (NULL));
-    return GST_FLOW_ERROR;
+
+  /* map inbuf -> EGL */
+  if (NvBufSurfaceMapEglImage (surface, -1) != 0) {
+    g_print ("Error: Could not map EglImage from NvBufSurface for dsexample\n");
+    goto error;
+  }
+  
+  if (cuGraphicsEGLRegisterImage (&pResource,
+        surface->surfaceList[0].mappedAddr.eglImage,
+        CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE) != CUDA_SUCCESS) {
+    g_print ("Error: Failed to register EGLImage in cuda\n");
+    goto error;
   }
 
-  if (dsexample->process_full_frame) {
-    for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;
-      l_frame = l_frame->next)
-    {
-      frame_meta = (NvDsFrameMeta *) (l_frame->data);
-      NvOSD_RectParams rect_params;
-
-      /* Scale the entire frame to processing resolution */
-      rect_params.left = 0;
-      rect_params.top = 0;
-      rect_params.width = dsexample->video_info.width;
-      rect_params.height = dsexample->video_info.height;
-
-      /* Scale and convert the frame */
-      if (get_converted_mat (dsexample, surface, i, &rect_params,
-            scale_ratio, dsexample->video_info.width,
-            dsexample->video_info.height) != GST_FLOW_OK) {
-        goto error;
-      }
+  if (cuGraphicsResourceGetMappedEglFrame (&eglFrame,
+        pResource, 0, 0) != CUDA_SUCCESS) {
+    g_print ("Error: Failed to get mapped EGL Frame\n");
+    goto error;
+  }
+  cuCtxSynchronize();
+
+
+  /* inter_buf -> VPI */
+  memset(&data, 0, sizeof(data));
+  data.format = VPI_IMAGE_FORMAT_RGBA8;
+  data.numPlanes = surface->surfaceList[0].planeParams.num_planes;
+  for(i=0; i<data.numPlanes; i++) {
+    data.planes[i].width = surface->surfaceList[0].planeParams.width[i];
+    data.planes[i].height = surface->surfaceList[0].planeParams.height[i];
+    data.planes[i].pitchBytes = surface->surfaceList[0].planeParams.pitch[i];
+    data.planes[i].data = eglFrame.frame.pPitch[i];
+  }
+  CHECK_VPI_STATUS(vpiImageCreateCUDAMemWrapper(&data, 0, &img));
+  CHECK_VPI_STATUS(vpiImageCreate(data.planes[0].width, data.planes[0].height, VPI_IMAGE_FORMAT_RGBA8, 0, &out));
 
-      /* Process to get the output */
-      output =
-          DsExampleProcess (dsexample->dsexamplelib_ctx,
-          dsexample->cvmat->data);
-      /* Attach the metadata for the full frame */
-      attach_metadata_full_frame (dsexample, frame_meta, scale_ratio, output, i);
-      i++;
-      free (output);
-    }
+  /* Apply warping */
+  VPIPerspectiveTransform t1, t2, P, tmp, xform;
 
-  } else {
-    /* Using object crops as input to the algorithm. The objects are detected by
-     * the primary detector */
-    NvDsMetaList * l_obj = NULL;
-    NvDsObjectMeta *obj_meta = NULL;
-
-#ifndef __aarch64__
-    if (dsexample->blur_objects) {
-      if (surface->memType != NVBUF_MEM_CUDA_UNIFIED){
-        GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-            ("%s:need NVBUF_MEM_CUDA_UNIFIED memory for opencv blurring",__func__), (NULL));
-        return GST_FLOW_ERROR;
-      }
-    }
-#endif
+  t1[0][0] = 1; t1[0][1] = 0; t1[0][2] = -data.planes[0].width / 2.0f;
+  t1[1][0] = 0; t1[1][1] = 1; t1[1][2] = -data.planes[0].height / 2.0f;
+  t1[2][0] = 0; t1[2][1] = 0; t1[2][2] = 1;
 
-    for (l_frame = batch_meta->frame_meta_list; l_frame != NULL;
-      l_frame = l_frame->next)
-    {
-      frame_meta = (NvDsFrameMeta *) (l_frame->data);
-      cv::Mat in_mat;
-
-      if (dsexample->blur_objects) {
-        /* Map the buffer so that it can be accessed by CPU */
-        if (surface->surfaceList[frame_meta->batch_id].mappedAddr.addr[0] == NULL){
-          if (NvBufSurfaceMap (surface, frame_meta->batch_id, 0, NVBUF_MAP_READ_WRITE) != 0){
-            GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-                ("%s:buffer map to be accessed by CPU failed", __func__), (NULL));
-            return GST_FLOW_ERROR;
-          }
-        }
-
-        /* Cache the mapped data for CPU access */
-        NvBufSurfaceSyncForCpu (surface, frame_meta->batch_id, 0);
-
-        in_mat =
-            cv::Mat (surface->surfaceList[frame_meta->batch_id].planeParams.height[0],
-            surface->surfaceList[frame_meta->batch_id].planeParams.width[0], CV_8UC4,
-            surface->surfaceList[frame_meta->batch_id].mappedAddr.addr[0],
-            surface->surfaceList[frame_meta->batch_id].planeParams.pitch[0]);
-      }
+  t2[0][0] = 1; t2[0][1] = 0; t2[0][2] = data.planes[0].width / 2.0f;
+  t2[1][0] = 0; t2[1][1] = 1; t2[1][2] = data.planes[0].height / 2.0f;
+  t2[2][0] = 0; t2[2][1] = 0; t2[2][2] = 1;
 
-      for (l_obj = frame_meta->obj_meta_list; l_obj != NULL;
-          l_obj = l_obj->next)
-      {
-        obj_meta = (NvDsObjectMeta *) (l_obj->data);
-
-        if (dsexample->blur_objects) {
-          /* gaussian blur the detected objects using opencv */
-          if (blur_objects (dsexample, frame_meta->batch_id,
-            &obj_meta->rect_params, in_mat) != GST_FLOW_OK) {
-          /* Error in blurring, skip processing on object. */
-            GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-            ("blurring the object failed"), (NULL));
-            if (NvBufSurfaceUnMap (surface, frame_meta->batch_id, 0)){
-              GST_ELEMENT_ERROR (dsexample, STREAM, FAILED,
-                ("%s:buffer unmap to be accessed by CPU failed", __func__), (NULL));
-            }
-            return GST_FLOW_ERROR;
-          }
-          continue;
-        }
-
-        /* Should not process on objects smaller than MIN_INPUT_OBJECT_WIDTH x MIN_INPUT_OBJECT_HEIGHT
-         * since it will cause hardware scaling issues. */
-        if (obj_meta->rect_params.width < MIN_INPUT_OBJECT_WIDTH ||
-            obj_meta->rect_params.height < MIN_INPUT_OBJECT_HEIGHT)
-          continue;
-
-        /* Crop and scale the object */
-        if (get_converted_mat (dsexample,
-              surface, frame_meta->batch_id, &obj_meta->rect_params,
-              scale_ratio, dsexample->video_info.width,
-              dsexample->video_info.height) != GST_FLOW_OK) {
-          /* Error in conversion, skip processing on object. */
-          continue;
-        }
-
-        /* Process the object crop to obtain label */
-        output = DsExampleProcess (dsexample->dsexamplelib_ctx,
-            dsexample->cvmat->data);
-
-        /* Attach labels for the object */
-        attach_metadata_object (dsexample, obj_meta, output);
-
-        free (output);
-      }
+  v1 = sin(dsexample->frame_num / 30.0 * 2 * M_PI / 2) * 0.0005f;
+  v2 = cos(dsexample->frame_num / 30.0 * 2 * M_PI / 3) * 0.0005f;
 
-      if (dsexample->blur_objects) {
-      /* Cache the mapped data for device access */
-        NvBufSurfaceSyncForDevice (surface, frame_meta->batch_id, 0);
-
-#ifdef DSEXAMPLE_DEBUG
-        /* Use openCV to remove padding and convert RGBA to BGR. Can be skipped if
-        * algorithm can handle padded RGBA data. */
-#if (CV_MAJOR_VERSION >= 4)
-        cv::cvtColor (in_mat, *dsexample->cvmat, cv::COLOR_RGBA2BGR);
-#else
-        cv::cvtColor (in_mat, *dsexample->cvmat, CV_RGBA2BGR);
-#endif
-        /* used to dump the converted mat to files for debug */
-        static guint cnt = 0;
-        cv::imwrite("out_" + std::to_string (cnt) + ".jpeg", *dsexample->cvmat);
-        cnt++;
-#endif
-      }
-    }
+  P[0][0] = 0.66; P[0][1] = 0;    P[0][2] = 0;
+  P[1][0] = 0;    P[1][1] = 0.66; P[1][2] = 0;
+  P[2][0] = v1;   P[2][1] = v2;   P[2][2] = 1;
+
+  matrix_multiply(tmp, P, t1);
+  matrix_multiply(xform, t2, tmp);
+
+//  CHECK_VPI_STATUS(vpiSubmitConvertImageFormat(dsexample->vpi_stream, VPI_BACKEND_CUDA, img, out, NULL));
+  CHECK_VPI_STATUS(vpiSubmitPerspectiveWarp(dsexample->vpi_stream, 0, dsexample->warp, img, xform, out
+                                              , VPI_INTERP_LINEAR, VPI_BORDER_ZERO, 0));
+  CHECK_VPI_STATUS(vpiSubmitConvertImageFormat(dsexample->vpi_stream, VPI_BACKEND_CUDA, out, img, NULL));
+  CHECK_VPI_STATUS(vpiStreamSync(dsexample->vpi_stream));
+  vpiImageDestroy(img);
+  vpiImageDestroy(out);
+
+  cuCtxSynchronize();
+  if (cuGraphicsUnregisterResource(pResource) != CUDA_SUCCESS) {
+    g_print ("Error: Failed to unregister EGLImage in cuda\n");
+    goto error;
+  }
+
+  if (NvBufSurfaceUnMapEglImage (surface, 0) != CUDA_SUCCESS) {
+    g_print ("Error: Failed to unmap EGLImage\n");
+    goto error;
   }
-  flow_ret = GST_FLOW_OK;
 
+  flow_ret = GST_FLOW_OK;
+  dsexample->last_flow_ret = flow_ret;
 error:
 
   nvds_set_output_system_timestamp (inbuf, GST_ELEMENT_NAME (dsexample));
@@ -845,125 +524,6 @@ error:
   return flow_ret;
 }
 
-/**
- * Attach metadata for the full frame. We will be adding a new metadata.
- */
-static void
-attach_metadata_full_frame (GstDsExample * dsexample, NvDsFrameMeta *frame_meta,
-    gdouble scale_ratio, DsExampleOutput * output, guint batch_id)
-{
-  NvDsBatchMeta *batch_meta = frame_meta->base_meta.batch_meta;
-  NvDsObjectMeta *object_meta = NULL;
-  static gchar font_name[] = "Serif";
-  GST_DEBUG_OBJECT (dsexample, "Attaching metadata %d\n", output->numObjects);
-
-  for (gint i = 0; i < output->numObjects; i++) {
-    DsExampleObject *obj = &output->object[i];
-    object_meta = nvds_acquire_obj_meta_from_pool(batch_meta);
-    NvOSD_RectParams & rect_params = object_meta->rect_params;
-    NvOSD_TextParams & text_params = object_meta->text_params;
-
-    /* Assign bounding box coordinates */
-    rect_params.left = obj->left;
-    rect_params.top = obj->top;
-    rect_params.width = obj->width;
-    rect_params.height = obj->height;
-
-    /* Semi-transparent yellow background */
-    rect_params.has_bg_color = 0;
-    rect_params.bg_color = (NvOSD_ColorParams) {
-    1, 1, 0, 0.4};
-    /* Red border of width 6 */
-    rect_params.border_width = 3;
-    rect_params.border_color = (NvOSD_ColorParams) {
-    1, 0, 0, 1};
-
-    /* Scale the bounding boxes proportionally based on how the object/frame was
-     * scaled during input */
-    rect_params.left /= scale_ratio;
-    rect_params.top /= scale_ratio;
-    rect_params.width /= scale_ratio;
-    rect_params.height /= scale_ratio;
-    GST_DEBUG_OBJECT (dsexample, "Attaching rect%d of batch%u"
-        "  left->%f top->%f width->%f"
-        " height->%f label->%s\n", i, batch_id, rect_params.left,
-        rect_params.top, rect_params.width, rect_params.height, obj->label);
-
-    object_meta->object_id = UNTRACKED_OBJECT_ID;
-    g_strlcpy (object_meta->obj_label, obj->label, MAX_LABEL_SIZE);
-    /* display_text required heap allocated memory */
-    text_params.display_text = g_strdup (obj->label);
-    /* Display text above the left top corner of the object */
-    text_params.x_offset = rect_params.left;
-    text_params.y_offset = rect_params.top - 10;
-    /* Set black background for the text */
-    text_params.set_bg_clr = 1;
-    text_params.text_bg_clr = (NvOSD_ColorParams) {
-    0, 0, 0, 1};
-    /* Font face, size and color */
-    text_params.font_params.font_name = font_name;
-    text_params.font_params.font_size = 11;
-    text_params.font_params.font_color = (NvOSD_ColorParams) {
-    1, 1, 1, 1};
-
-    nvds_add_obj_meta_to_frame(frame_meta, object_meta, NULL);
-    frame_meta->bInferDone = TRUE;
-  }
-}
-
-/**
- * Only update string label in an existing object metadata. No bounding boxes.
- * We assume only one label per object is generated
- */
-static void
-attach_metadata_object (GstDsExample * dsexample, NvDsObjectMeta * obj_meta,
-    DsExampleOutput * output)
-{
-  if (output->numObjects == 0)
-    return;
-  NvDsBatchMeta *batch_meta = obj_meta->base_meta.batch_meta;
-
-  NvDsClassifierMeta *classifier_meta =
-    nvds_acquire_classifier_meta_from_pool (batch_meta);
-
-  classifier_meta->unique_component_id = dsexample->unique_id;
-
-  NvDsLabelInfo *label_info =
-    nvds_acquire_label_info_meta_from_pool (batch_meta);
-  g_strlcpy (label_info->result_label, output->object[0].label, MAX_LABEL_SIZE);
-  nvds_add_label_info_meta_to_classifier(classifier_meta, label_info);
-  nvds_add_classifier_meta_to_object (obj_meta, classifier_meta);
-
-  nvds_acquire_meta_lock (batch_meta);
-  NvOSD_TextParams & text_params = obj_meta->text_params;
-  NvOSD_RectParams & rect_params = obj_meta->rect_params;
-
-  /* Below code to display the result */
-  /* Set black background for the text
-   * display_text required heap allocated memory */
-  if (text_params.display_text) {
-    gchar *conc_string = g_strconcat (text_params.display_text, " ",
-        output->object[0].label, NULL);
-    g_free (text_params.display_text);
-    text_params.display_text = conc_string;
-  } else {
-    /* Display text above the left top corner of the object */
-    text_params.x_offset = rect_params.left;
-    text_params.y_offset = rect_params.top - 10;
-    text_params.display_text = g_strdup (output->object[0].label);
-    /* Font face, size and color */
-    text_params.font_params.font_name = (char *)"Serif";
-    text_params.font_params.font_size = 11;
-    text_params.font_params.font_color = (NvOSD_ColorParams) {
-    1, 1, 1, 1};
-    /* Set black background for the text */
-    text_params.set_bg_clr = 1;
-    text_params.text_bg_clr = (NvOSD_ColorParams) {
-    0, 0, 0, 1};
-  }
-  nvds_release_meta_lock (batch_meta);
-}
-
 /**
  * Boiler plate for registering a plugin and an element.
  */
diff --git a/gstdsexample.h b/gstdsexample.h
index c5d668c..743589d 100644
--- a/gstdsexample.h
+++ b/gstdsexample.h
@@ -29,6 +29,7 @@
 /* Open CV headers */
 #include "opencv2/imgproc/imgproc.hpp"
 #include "opencv2/highgui/highgui.hpp"
+#include <vpi/Stream.h>
 
 #include <cuda.h>
 #include <cuda_runtime.h>
@@ -75,17 +76,11 @@ struct _GstDsExample
   // Frame number of the current input buffer
   guint64 frame_num;
 
-  // CUDA Stream used for allocating the CUDA task
-  cudaStream_t cuda_stream;
+  // VPI stream
+  VPIStream vpi_stream;
 
-  // Host buffer to store RGB data for use by algorithm
-  void *host_rgb_buf;
-
-  // the intermediate scratch buffer for conversions RGBA
-  NvBufSurface *inter_buf;
-
-  // OpenCV mat containing RGB data
-  cv::Mat *cvmat;
+  // VPI payload
+  VPIPayload warp;
 
   // Input video info (resolution, color format, framerate, etc)
   GstVideoInfo video_info;
@@ -100,11 +95,8 @@ struct _GstDsExample
   // GPU ID on which we expect to execute the task
   guint gpu_id;
 
-  // Boolean indicating if entire frame or cropped objects should be processed
-  gboolean process_full_frame;
-
-  // Boolean indicating if to blur the detected objects
-  gboolean blur_objects;
+  /** GstFlowReturn returned by the latest buffer pad push. */
+  GstFlowReturn last_flow_ret;
 };
 
 // Boiler plate stuff
