[Filter/MvNCSDK] Implement callbacks for open/close of filter framework
authorWook Song <wook16.song@samsung.com>
Thu, 23 May 2019 08:55:22 +0000 (17:55 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Mon, 27 May 2019 05:58:55 +0000 (14:58 +0900)
This patch implements callback functions for opening and closing
GstTensorFilterFramework for the Intel Movidius Neural Compute Stick
sub-plugin of tensor_filter.

Signed-off-by: Wook Song <wook16.song@samsung.com>
ext/nnstreamer/tensor_filter/tensor_filter_movidius_ncsdk2.c

index 625cb4a..82afc2f 100644 (file)
  * @bug     No known bugs except for NYI items
  *
  * This is the per-NN-framework plugin (Intel Movidius NCSDK2) for tensor_filter.
- * TODO: Fill in "GstTensorFilterFramework" for tensor_filter.h/c
- *
  */
 
+#include <fcntl.h>
 #include <glib.h>
+#include <glib/gstdio.h>
+#include <gst/gst.h>
 #include <mvnc2/mvnc.h>
 #include <nnstreamer_plugin_api_filter.h>
+#include <sys/types.h>
+#include <sys/stat.h>
 
 void init_filter_mvncsdk2 (void) __attribute__ ((constructor));
 void fini_filter_mvncsdk2 (void) __attribute__ ((destructor));
 
+enum _private_constants
+{
+  NNS_MVNCSDK2_SUPPORT_MAX_NUMS_DEVICES = 8,
+  NNS_MVNCSDK2_SUPPORT_API_MAJOR_VER = 2,
+  NNS_MVNCSDK2_API_VER_ARRAY_SIZE = NC_VERSION_MAX_SIZE,
+  NNS_MVNCSDK2_MAX_NUM_ELEM_IN_FIFO = 2,
+};
+
+static const char NNS_MVNCSDK2_NAME_INPUT_FIFO[] = "INPUT_FIFO";
+static const char NNS_MVNCSDK2_NAME_OUTPUT_FIFO[] = "OUTPUT_FIFO";
+
 /**
  * @brief internal data of mvncsdk2
  */
 typedef struct _mvncsdk2_data
 {
-  void *private_data;
+  /* Variables of the data types from mvnc.h */
+  struct ncDeviceHandle_t *handle_device; /** handle for Intel Movidius device */
+  struct ncGraphHandle_t *handle_graph; /** handle for graph (model) */
+  struct ncTensorDescriptor_t tensor_desc_input; /** description of input tensor */
+  struct ncTensorDescriptor_t tensor_desc_output; /** description of output tenser */
+  struct ncFifoHandle_t *handle_fifo_input; /** handle for input fifo (buffer) */
+  struct ncFifoHandle_t *handle_fifo_output; /** handle for output fifo (buffer) */
+  /* Normal variables */
+  gint32 idx_device;  /** index of device to use (Q. is it necessary?) */
 } mvncsdk2_data;
 
 /**
  * @brief Free privateData and move on.
+ * @param prop : property of tensor_filter instance
+ * @param private_data : movidius-ncsdk2 plugin's private data
  */
 static void
 _mvncsdk2_close (const GstTensorFilterProperties * prop, void **private_data)
 {
-  return;
+  mvncsdk2_data *pdata = *private_data;
+
+  if (pdata != NULL) {
+    ncGraphDestroy (&(pdata->handle_graph));
+    ncFifoDestroy (&(pdata->handle_fifo_output));
+    ncFifoDestroy (&(pdata->handle_fifo_input));
+    ncDeviceDestroy (&(pdata->handle_device));
+
+    g_free (pdata);
+    *private_data = NULL;
+  }
 }
 
 /**
  * @brief The open callback for GstTensorFilterFramework. Called before anything else
  * @param prop : property of tensor_filter instance
- * @param private_data : movidius-ncsdk2  plugin's private data
- * @todo : fill this function
+ * @param private_data : movidius-ncsdk2 plugin's private data
+ * @return 0 if OK. -1 if error.
  */
 static int
 _mvncsdk2_open (const GstTensorFilterProperties * prop, void **private_data)
 {
+  /* Variables of the data types from mvnc.h */
+  struct ncDeviceHandle_t *handle_device = NULL;
+  struct ncGraphHandle_t *handle_graph = NULL;
+  struct ncTensorDescriptor_t tensor_desc_input;
+  struct ncTensorDescriptor_t tensor_desc_output;
+  struct ncFifoHandle_t *handle_fifo_input;
+  struct ncFifoHandle_t *handle_fifo_output;
+  ncStatus_t ret_code;
+  /* Normal variables */
+  GMappedFile *file_model = NULL;
+  mvncsdk2_data *pdata = NULL;
+  gint32 sdk_ver[NNS_MVNCSDK2_API_VER_ARRAY_SIZE];
+  guint32 size_sdk_ver = sizeof (sdk_ver);
+  gint32 idx_dev = -1;
+  guint32 len_model_file;
+  void *buf_model_file;
+  guint32 len;
+  gint32 i;
+
+  /* 0. Check the API version */
+  ret_code = ncGlobalGetOption (NC_RO_API_VERSION, sdk_ver, &size_sdk_ver);
+  if ((ret_code != NC_OK) && (sdk_ver[0] != NNS_MVNCSDK2_SUPPORT_API_MAJOR_VER)) {
+    g_printerr
+        ("The major version number of the MVNCSDK API should be %d, not %d\n",
+        NNS_MVNCSDK2_SUPPORT_API_MAJOR_VER, sdk_ver[0]);
+    return -1;
+  }
+
+  /**
+   * 1. Initialize device handle:
+   *  we do not know how many devices are plugged and used. Therefore,
+   *  let's try all the possible device indices (currently,
+   *  0 ~ NNS_MVNCSDK2_SUPPORT_MAX_NUMS_DEVICES) here.
+   */
+  for (i = 0; i < NNS_MVNCSDK2_SUPPORT_MAX_NUMS_DEVICES; ++i) {
+    ret_code = ncDeviceCreate (i, &handle_device);
+    if (ret_code == NC_OK) {
+      idx_dev = i;
+      break;
+    } else {
+      GST_WARNING ("Failed to create device handle at index %d: "
+          "%d is returned\n", i, ret_code);
+    }
+  }
+  if ((ret_code != NC_OK) && (i == NNS_MVNCSDK2_SUPPORT_MAX_NUMS_DEVICES)) {
+    g_printerr ("Cannot create device handle: no available device found\n");
+    return -1;
+  }
+
+  /**
+   * 2. Initialize graph (model) handle
+   */
+  ret_code = ncGraphCreate (prop->model_file, &handle_graph);
+  if (ret_code != NC_OK) {
+    g_printerr ("Cannot create graph handle for \"%s\"\n", prop->model_file);
+    goto err_destroy_device_h;
+  }
+
+  /**
+   * 3. Open device using device handle
+   */
+  ret_code = ncDeviceOpen (handle_device);
+  if (ret_code != NC_OK) {
+    g_printerr ("Cannot open device at index %d\n", idx_dev);
+    goto err_destroy_graph_h;
+  }
+
+  /**
+   * 4. Send model (graph) to the device
+   */
+  file_model = g_mapped_file_new (prop->model_file, FALSE, NULL);
+  if (file_model == NULL) {
+    g_printerr ("Failed to g_mapped_file_new for the model file, \"%s\"\n",
+        prop->model_file);
+    goto err_destroy_graph_h;
+  }
+
+  /* Warning: conversion unsigned long to unsigned int */
+  len_model_file = g_mapped_file_get_length (file_model);
+  buf_model_file = (void *) g_mapped_file_get_contents (file_model);
+
+  /* Actually, send the model to the device */
+  ret_code = ncGraphAllocate (handle_device, handle_graph, buf_model_file,
+      len_model_file);
+  /** After allocating, we do not need file_model any more */
+  g_mapped_file_unref (file_model);
+  if (ret_code != NC_OK) {
+    g_printerr ("Cannot send the model file to the device\n");
+    goto err_destroy_graph_h;
+  }
+
+  /**
+   * 5. Get the tensor desciptions for input and output form allocated model
+   */
+  len = sizeof (tensor_desc_input);
+  ret_code =
+      ncGraphGetOption (handle_graph, NC_RO_GRAPH_INPUT_TENSOR_DESCRIPTORS,
+      &tensor_desc_input, &len);
+  if (ret_code != NC_OK) {
+    g_printerr ("Cannot get the tensor description for input\n");
+    goto err_destroy_graph_h;
+  }
+
+  len = sizeof (tensor_desc_output);
+  ret_code =
+      ncGraphGetOption (handle_graph, NC_RO_GRAPH_OUTPUT_TENSOR_DESCRIPTORS,
+      &tensor_desc_output, &len);
+  if (ret_code != NC_OK) {
+    g_printerr ("Cannot get the tensor description for output\n");
+    goto err_destroy_graph_h;
+  }
+  /**
+   * 6. Create fifo handles for input and output tensors
+   */
+  ret_code = ncFifoCreate (NNS_MVNCSDK2_NAME_INPUT_FIFO,
+      NC_FIFO_HOST_WO, &handle_fifo_input);
+  if (ret_code != NC_OK) {
+    g_printerr ("Cannot create FIFO handle for input tensor\n");
+    goto err_destroy_graph_h;
+  }
+
+  ret_code = ncFifoCreate (NNS_MVNCSDK2_NAME_OUTPUT_FIFO,
+      NC_FIFO_HOST_RO, &handle_fifo_output);
+  if (ret_code != NC_OK) {
+    g_printerr ("Cannot create FIFO handle for output tensor\n");
+    goto err_destroy_graph_h;
+  }
+
+  /**
+   * 7. Allocate fifos for input and output tensors
+   */
+  ret_code = ncFifoAllocate (handle_fifo_input, handle_device,
+      &tensor_desc_input, NNS_MVNCSDK2_MAX_NUM_ELEM_IN_FIFO);
+  if (ret_code != NC_OK) {
+    g_printerr ("Cannot allocate FIFO in the device for input tensor\n");
+    goto err_destroy_graph_h;
+  }
+
+  ret_code = ncFifoAllocate (handle_fifo_output, handle_device,
+      &tensor_desc_output, NNS_MVNCSDK2_MAX_NUM_ELEM_IN_FIFO);
+  if (ret_code != NC_OK) {
+    g_printerr ("Cannot allocate FIFO in the device for output tensor\n");
+    ncFifoDestroy (&handle_fifo_input);
+    goto err_destroy_graph_h;
+  }
+
+  /**
+   * 8. Create private data and fill it
+   */
+  pdata = g_try_new0 (mvncsdk2_data, 1);
+  if (pdata == NULL) {
+    g_printerr ("Cannot allocate memory for private data structure\n");
+    goto err_destroy_fifo_h;
+  }
+
+  pdata->handle_device = handle_device;
+  pdata->handle_graph = handle_graph;
+  pdata->handle_fifo_input = handle_fifo_input;
+  pdata->handle_fifo_output = handle_fifo_output;
+  pdata->tensor_desc_input = tensor_desc_input;
+  pdata->tensor_desc_output = tensor_desc_output;
+  *private_data = pdata;
+
   return 0;
+
+err_destroy_fifo_h:
+  ncFifoDestroy (&handle_fifo_input);
+  ncFifoDestroy (&handle_fifo_output);
+err_destroy_graph_h:
+  ncGraphDestroy (&handle_graph);
+err_destroy_device_h:
+  ncDeviceDestroy (&handle_device);
+
+  g_printerr ("Failed to initialize %s tensor_filter framework", prop->fwname);
+
+  return -1;
 }
 
 /**
@@ -88,8 +297,8 @@ _mvncsdk2_invoke (const GstTensorFilterProperties * prop, void **private_data,
  * @todo : fill this function
  */
 static int
-_mvncsdk2_getInputDim (const GstTensorFilterProperties * prop, void **private_data,
-    GstTensorsInfo * info)
+_mvncsdk2_getInputDim (const GstTensorFilterProperties * prop,
+    void **private_data, GstTensorsInfo * info)
 {
   return 0;
 }