[PythonFilter/API] Add a python module to provide NNS-related APIs
authorDongju Chae <dongju.chae@samsung.com>
Thu, 11 Apr 2019 08:27:58 +0000 (17:27 +0900)
committerwooksong <wook16.song@samsung.com>
Fri, 12 Apr 2019 07:14:52 +0000 (16:14 +0900)
It's a python module which a user will import in a python script.
Currently, only 'TensorShape' type object is supported.
I am currently considering other useful APIs.

Signed-off-by: Dongju Chae <dongju.chae@samsung.com>
ext/nnstreamer/tensor_filter/tensor_filter_python_api.c [new file with mode: 0644]

diff --git a/ext/nnstreamer/tensor_filter/tensor_filter_python_api.c b/ext/nnstreamer/tensor_filter/tensor_filter_python_api.c
new file mode 100644 (file)
index 0000000..d2826a1
--- /dev/null
@@ -0,0 +1,218 @@
+/**
+ * GStreamer Tensor_Filter, Python Module
+ * Copyright (C) 2019 Dongju Chae <dongju.chae@samsung.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ */
+/**
+ * @file       tensor_filter_python_api.c
+ * @date       10 Apr 2019
+ * @brief      python helper structure for nnstreamer tensor_filter
+ * @see                http://github.com/nnsuite/nnstreamer
+ * @author     Dongju Chae <dongju.chae@samsung.com>
+ * @bug                No known bugs except for NYI items
+ */
+
+#include "tensor_filter_python_core.h"
+
+/** @brief object structure for custom Python type: TensorShape */
+typedef struct {
+  PyObject_HEAD
+  PyObject *dims;
+  PyArray_Descr* type;
+} TensorShapeObject;
+
+/** 
+ * @brief method impl. for setDims
+ * @param self : Python type object 
+ * @param args : arguments for the method
+ */
+static PyObject *
+TensorShape_setDims(TensorShapeObject *self, PyObject *args) {
+  PyObject *dims = args;
+  PyObject *new_dims;
+
+  /** PyArg_ParseTuple() returns borrowed references */
+  if (!PyArg_ParseTuple(args, "O", &dims))
+    Py_RETURN_NONE;
+
+  if (PyList_Size(dims) < NNS_TENSOR_RANK_LIMIT) {
+    int i;
+    for (i = 0; i < NNS_TENSOR_RANK_LIMIT - PyList_Size(dims); i++)
+      /** fill '1's in remaining slots */
+      PyList_Append(dims, PyLong_FromLong(1)); 
+    new_dims = dims;
+    Py_XINCREF(new_dims);
+  } else {
+    /** PyList_GetSlice() returns new reference */
+    new_dims = PyList_GetSlice(dims, 0, NNS_TENSOR_RANK_LIMIT);
+  }
+
+  /** swap 'self->dims' */
+  Py_XDECREF(self->dims);
+  self->dims = new_dims;
+
+  Py_RETURN_NONE;
+}
+
+/** 
+ * @brief method impl. for getDims
+ * @param self : Python type object 
+ * @param args : arguments for the method
+ */
+static PyObject *
+TensorShape_getDims(TensorShapeObject *self, PyObject *args) {
+  return Py_BuildValue("O", self->dims);
+}
+
+/**
+ * @brief method impl. for getType
+ * @param self : Python type object 
+ * @param args : arguments for the method
+ */
+static PyObject *
+TensorShape_getType(TensorShapeObject *self, PyObject *args) {
+  return Py_BuildValue("O", self->type);
+}
+
+/** 
+ * @brief new callback for custom type object 
+ * @param self : Python type object 
+ * @param args : arguments for the method
+ * @param kw : keywords for the arguments
+ */
+static PyObject *
+TensorShape_new(PyTypeObject *type, PyObject *args, PyObject *kw) {
+  TensorShapeObject *self = (TensorShapeObject *) type->tp_alloc(type, 0);
+
+  g_assert(self);
+
+  /** Assign default values */
+  self->dims = PyList_New(0);
+  self->type = PyArray_DescrFromType(NPY_UINT8);
+  Py_XINCREF(self->type);
+
+  return (PyObject *) self;
+}
+
+/** 
+ * @brief init callback for custom type object 
+ * @param self : Python type object 
+ * @param args : arguments for the method
+ * @param kw : keywords for the arguments
+ */
+static int
+TensorShape_init(TensorShapeObject *self, PyObject *args, PyObject *kw) {
+  char *keywords[] = {"dims", "type", NULL};
+  PyObject *dims = NULL;
+  PyObject *type = NULL;
+
+  if (!PyArg_ParseTupleAndKeywords(args, kw, "|OO", keywords, &dims, &type))
+    return -1;
+
+  if (dims) {
+    PyObject *none = PyObject_CallMethod((PyObject*) self, (char*) "setDims", "O", dims);
+    Py_XDECREF(none);
+  }
+
+  if (type) {
+    PyArray_Descr* dtype;
+    if (PyArray_DescrConverter(type, &dtype) != NPY_FAIL) {
+      /** swap 'self->type' */
+      Py_XDECREF(self->type);
+      self->type = dtype;
+      Py_XINCREF(dtype);
+    } else
+      g_critical("Wrong data type");
+  }
+
+  return 0;
+}
+
+/** 
+ * @brief dealloc callback for custom type object 
+ * @param self : Python type object 
+ */
+static void
+TensorShape_dealloc(TensorShapeObject *self) {
+  Py_XDECREF(self->dims);
+  Py_XDECREF(self->type);
+  Py_TYPE(self)->tp_free((PyObject *) self);
+}
+
+/** @brief members for custom type object */
+static PyMemberDef TensorShape_members[] = {
+  {"dims", T_OBJECT_EX, offsetof(TensorShapeObject, dims), 0, NULL},
+  {"type", T_OBJECT_EX, offsetof(TensorShapeObject, type), 0, NULL}
+};
+
+/** @brief methods for custom type object */
+static PyMethodDef TensorShape_methods[] = {
+  {"setDims", (PyCFunction)TensorShape_setDims, METH_VARARGS | METH_KEYWORDS, NULL},
+  {"getDims", (PyCFunction)TensorShape_getDims, METH_VARARGS | METH_KEYWORDS, NULL},
+  {"getType", (PyCFunction)TensorShape_getType, METH_VARARGS | METH_KEYWORDS, NULL},
+  {NULL, NULL, 0, NULL}
+};
+
+/** @brief Structure for custom type object */
+static PyTypeObject TensorShapeType = {
+  PyVarObject_HEAD_INIT(NULL, 0)
+  .tp_name = "nnstreamer_python.TensorShape",
+  .tp_doc = "TensorShape type",
+  .tp_basicsize = sizeof(TensorShapeObject),
+  .tp_itemsize = 0,
+  .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
+  .tp_new = TensorShape_new,
+  .tp_init = (initproc) TensorShape_init,
+  .tp_dealloc = (destructor) TensorShape_dealloc,
+  .tp_members = TensorShape_members,
+  .tp_methods = TensorShape_methods
+};
+
+#if PY_VERSION_HEX >= 0x03000000
+#define RETVAL(x) x
+static PyModuleDef nnstreamer_python_module = {
+  PyModuleDef_HEAD_INIT, "nnstreamer_python3", NULL, -1, NULL
+};
+/** @brief module initialization (python 3.x) */
+PyMODINIT_FUNC
+PyInit_nnstreamer_python3(void) {
+#else
+#define RETVAL(x)
+static PyMethodDef nnstreamer_python_methods[] = {
+  {NULL, NULL}
+};
+/** @brief module initialization (python 2.x) */
+PyMODINIT_FUNC
+initnnstreamer_python2(void) {
+#endif
+  PyObject *type_object = (PyObject*) &TensorShapeType;
+  PyObject *module;
+#if PY_VERSION_HEX >= 0x03000000
+  module = PyModule_Create(&nnstreamer_python_module);
+#else
+  module = Py_InitModule("nnstreamer_python2", nnstreamer_python_methods);
+#endif
+  if (module == NULL) 
+    return RETVAL(NULL);
+
+  /** For numpy array init. */
+  import_array();
+
+  /** Check TensorShape type */
+  g_assert(!(PyType_Ready(&TensorShapeType) < 0));
+
+  Py_INCREF(type_object);
+  PyModule_AddObject(module, "TensorShape", type_object);
+
+  return RETVAL(module);
+}