[Tizen/API] API implementation skeleton
authorMyungJoo Ham <myungjoo.ham@samsung.com>
Fri, 8 Mar 2019 06:18:49 +0000 (15:18 +0900)
committerMyungJoo Ham <myungjoo.ham@samsung.com>
Wed, 20 Mar 2019 07:23:17 +0000 (16:23 +0900)
This includes Tizen API implementation skeleton
and a constructor of a pipeline.

Signed-off-by: MyungJoo Ham <myungjoo.ham@samsung.com>
meson.build
meson_options.txt
packaging/capi-nnstreamer.manifest [new file with mode: 0644]
packaging/nnstreamer.spec
tizen-api/include/tizen-api-private.h
tizen-api/include/tizen-api.h
tizen-api/meson.build
tizen-api/src/tizen-api-pipeline.c [new file with mode: 0644]

index 7b475a6..99560c2 100644 (file)
@@ -124,6 +124,11 @@ subdir('gst')
 # Build ext subplugins
 subdir('ext')
 
+# Build Tizen CAPI
+if get_option('enable-tizen-capi')
+  subdir('tizen-api')
+endif
+
 # Build nnstreamer examples
 if get_option('enable-test') or get_option('install-example')
   subdir('nnstreamer_example')
index 7f2efc0..77b28d3 100644 (file)
@@ -5,3 +5,4 @@ option('enable-tensorflow', type: 'boolean', value: true)
 option('enable-tensorflow-mem-optmz', type: 'boolean', value: true)
 option('install-example', type: 'boolean', value: false)
 option('disable-audio-support', type: 'boolean', value: false)
+option('enable-tizen-capi', type: 'boolean', value: false)
diff --git a/packaging/capi-nnstreamer.manifest b/packaging/capi-nnstreamer.manifest
new file mode 100644 (file)
index 0000000..017d22d
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+ <request>
+    <domain name="_"/>
+ </request>
+</manifest>
index b0bb5e8..7291db2 100644 (file)
@@ -3,6 +3,9 @@
 %define                gstlibdir       %{_libdir}/%{gstpostfix}
 %define                nnstexampledir  /usr/lib/nnstreamer/bin
 
+# If it is tizen, we can export Tizen API packages.
+%bcond_with tizen
+
 Name:          nnstreamer
 Summary:       gstremaer plugins for neural networks
 # Synchronize the version information among Ubuntu, Tizen, Android, and Meson.
@@ -17,6 +20,9 @@ Packager:     MyungJoo Ham <myungjoo.ham@samsung.com>
 License:       LGPL-2.1
 Source0:       nnstreamer-%{version}.tar.gz
 Source1001:    nnstreamer.manifest
+%if %{with tizen}
+Source1002:    capi-nnstreamer.manifest
+%endif
 
 Requires:      gstreamer >= 1.8.0
 BuildRequires: gstreamer-devel
@@ -52,6 +58,12 @@ BuildRequires: tensorflow-devel
 BuildRequires: lcov
 # BuildRequires:       taos-ci-unittest-coverage-assessment
 %endif
+%if %{with tizen}
+BuildRequires: pkgconfig(capi-base-common)
+BuildRequires: pkgconfig(dlog)
+BuildRequires: gst-plugins-bad-devel
+BuildRequires: gst-plugins-base-devel
+%endif
 
 # Unit Testing Uses SSAT (hhtps://github.com/myungjoo/SSAT.git)
 BuildRequires: ssat
@@ -105,9 +117,33 @@ Example custom tensor_filter subplugins and
 plugins created for test purpose.
 
 
+%%%% THIS IS FOR TIZEN ONLY! %%%%
+%if %{with tizen}
+%package -n capi-nnstreamer
+Summary:       Tizen Native API for NNStreamer
+Group:         Multimedia/Framework
+Requires:      %{name} = %{version}-%{release}
+%description -n capi-nnstreamer
+Tizen Native API wrapper for NNStreamer.
+You can construct a data stream pipeline with neural networks easily.
+
+%package -n capi-nnstreamer-devel
+Summary:       Tizen Native API Devel Kit for NNStreamer
+Group:         Multimedia/Framework
+%description -n capi-nnstreamer-devel
+Developmental kit for Tizen Native NNStreamer API.
+%define api -Denable-tizen-capi=true
+%else
+%define api -Denable-tizen-capi=false
+%endif
+
 %prep
 %setup -q
 cp %{SOURCE1001} .
+%if %{with tizen}
+cp %{SOURCE1002} .
+cp tizen-api/LICENSE.Apache-2.0 LICENSE.APLv2
+%endif
 
 %build
 %if 0%{?testcoverage}
@@ -123,7 +159,7 @@ enable_tf=true
 enable_tf=false
 %endif
 
-meson --buildtype=plain --prefix=%{_prefix} --sysconfdir=%{_sysconfdir} --libdir=%{_libdir} --bindir=%{nnstexampledir} --includedir=%{_includedir} -Dinstall-example=true -Denable-tensorflow=${enable_tf} build
+meson --buildtype=plain --prefix=%{_prefix} --sysconfdir=%{_sysconfdir} --libdir=%{_libdir} --bindir=%{nnstexampledir} --includedir=%{_includedir} -Dinstall-example=true -Denable-tensorflow=${enable_tf} %{api} build
 
 ninja -C build %{?_smp_mflags}
 
@@ -215,8 +251,13 @@ popd
 %{_prefix}/lib/nnstreamer/filters/libnnstreamer_filter_tensorflow-lite.so
 
 %files devel
-%{_includedir}/nnstreamer/*
+%{_includedir}/nnstreamer/tensor_typedef.h
+%{_includedir}/nnstreamer/tensor_filter_custom.h
+%{_includedir}/nnstreamer/nnstreamer_plugin_api_filter.h
+%{_includedir}/nnstreamer/nnstreamer_plugin_api_decoder.h
+%{_includedir}/nnstreamer/nnstreamer_plugin_api.h
 %{_libdir}/*.a
+%exclude %{_libdir}/libcapi*.a
 %{_libdir}/pkgconfig/nnstreamer.pc
 
 %if 0%{?testcoverage}
@@ -230,6 +271,19 @@ popd
 %license LICENSE
 %{_prefix}/lib/nnstreamer/customfilters/*.so
 
+%if %{with tizen}
+%files -n capi-nnstreamer
+%manifest capi-nnstreamer.manifest
+%license LICENSE.APLv2
+%{_libdir}/libcapi-nnstreamer.so.*
+
+%files -n capi-nnstreamer-devel
+%{_includedir}/nnstreamer/tizen-api.h
+%{_libdir}/pkgconfig/capi-nnstreamer.pc
+%{_libdir}/libcapi-nnstreamer.so
+%{_libdir}/libcapi-nnstreamer.a
+%endif
+
 %changelog
 * Wed Mar 20 2019 MyungJoo Ham <myungjoo.ham@samsung.com>
 - Release of 0.1.2
index 12f90fe..4207de9 100644 (file)
 #define __TIZEN_NNSTREAMER_API_PRIVATE_H___
 
 #include <glib.h>
+#include <gmodule.h>
 #include <gst/gst.h>
+#include "tizen-api.h"
+#include <tizen_error.h>
+#include <nnstreamer/tensor_typedef.h>
+#include <gst/app/gstappsrc.h>
 
 #ifdef __cplusplus
 extern "C" {
 #endif /* __cplusplus */
 
 /**
+ * @brief Possible controls on elements of a pipeline.
+ */
+typedef enum {
+  NNSAPI_UNKNOWN = 0x0,
+  NNSAPI_SINK = 0x1,
+  NNSAPI_SRC = 0x2,
+  NNSAPI_VALVE = 0x3,
+  NNSAPI_SWITCH_INPUT = 0x8,
+  NNSAPI_SWITCH_OUTPUT = 0x9,
+} elementType;
+
+/**
+ * @brief Internal private representation of pipeline handle.
+ */
+typedef struct _nns_pipeline nns_pipeline;
+
+/**
+ * @brief An element that may be controlled individually in a pipeline.
+ */
+typedef struct _element {
+  GstElement *element; /**< The Sink/Src/Valve/Switch element */
+  nns_pipeline *pipe; /**< The main pipeline */
+  const char *name;
+  elementType type;
+  GstPad *src;
+  GstPad *sink; /**< Unref this at destroy */
+  GstTensorsInfo tensorsinfo;
+  size_t size;
+
+  GList *handles;
+  GMutex lock; /**< Lock for internal values */
+} element;
+
+/**
  * @brief Internal private representation of pipeline handle.
  * @detail This should not be exposed to applications
  */
-typedef struct _nns_pipeline {
-  GstElement *element;
-  GError *error;
-  GMutex lock;
-  /** @todo: add list of switches and valves for faster control */
-  /** @todo: add list of appsrc / tensorsink for faster stream */
-} nns_pipeline;
+struct _nns_pipeline {
+  GstElement *element;    /**< The pipeline itself (GstPipeline) */
+  GMutex lock;            /**< Lock for pipeline operations */
+  GHashTable *namednodes; /**< hash table of "element"s. */
+};
+
+/**
+ * @brief Internal private representation of sink handle of GstTensorSink
+ * @detail This represents a single instance of callback registration. This should not be exposed to applications.
+ */
+typedef struct _nns_sink {
+  nns_pipeline *pipe; /**< The pipeline, which is the owner of this nns_sink */
+  element *element;
+  guint32 id;
+  nns_sink_cb cb;
+  void *pdata;
+} nns_sink;
+
+/**
+ * @brief Internal private representation of src handle of GstAppSrc
+ * @detail This represents a single instance of registration. This should not be exposed to applications.
+ */
+typedef struct _nns_src {
+  nns_pipeline *pipe;
+  element *element;
+  guint32 id;
+} nns_src;
+
+/**
+ * @brief Internal private representation of switch handle (GstInputSelector, GstOutputSelector)
+ * @detail This represents a single instance of registration. This should not be exposed to applications.
+ */
+typedef struct _nns_switch {
+  nns_pipeline *pipe;
+  element *element;
+  guint32 id;
+} nns_switch;
+
+/**
+ * @brief Internal private representation of valve handle (GstValve)
+ * @detail This represents a single instance of registration. This should not be exposed to applications.
+ */
+typedef struct _nns_valve {
+  nns_pipeline *pipe;
+  element *element;
+  guint32 id;
+} nns_valve;
 
 #ifdef __cplusplus
 }
index 63b605b..604ba35 100644 (file)
@@ -41,31 +41,31 @@ extern "C" {
  * @brief A handle of an NNStreamer pipeline.
  * @since_tizen 5.5
  */
-typedef struct nns_pipeline *nns_pipeline_h;
+typedef void *nns_pipeline_h;
 
 /**
  * @brief A handle of a "sink node" of an NNStreamer pipeline
  * @since_tizen 5.5
  */
-typedef struct nns_sink *nns_sink_h;
+typedef void *nns_sink_h;
 
 /**
  * @brief A handle of a "src node" of an NNStreamer pipeline
  * @since_tizen 5.5
  */
-typedef struct nns_src *nns_src_h;
+typedef void *nns_src_h;
 
 /**
  * @brief A handle of a "switch" of an NNStreamer pipeline
  * @since_tizen 5.5
  */
-typedef struct nns_switch *nns_switch_h;
+typedef void *nns_switch_h;
 
 /**
  * @brief A handle of a "valve node" of an NNStreamer pipeline
  * @since_tizen 5.5
  */
-typedef struct nns_valve *nns_valve_h;
+typedef void *nns_valve_h;
 
 /**
  * @brief Enumeration for the error codes of NNStreamer Pipelines.
index e69de29..8d4b7b1 100644 (file)
@@ -0,0 +1,72 @@
+if meson.project_name() != 'nnstreamer'
+
+  project('capi-nnstreamer', 'c',
+    version: '0.1',
+    license: ['Apache2'],
+    meson_version: '>=0.40.0',
+    default_options: [
+      'werror=true',
+      'warning_level=1',
+      'c_std=c89'
+    ]
+  )
+
+  add_project_arguments('-DVERSION="'+meson.project_version()+'"', language: ['c', 'cpp'])
+
+  cc = meson.get_compiler('c')
+  cxx = meson.get_compiler('cpp')
+
+  gst_api_verision = '1.0'
+endif
+
+
+capi_main = [
+  'src/tizen-api-pipeline.c'
+]
+
+capi_devel_main = [
+  'include/tizen-api.h'
+]
+
+inc = include_directories('include')
+nninc = include_directories('../gst')
+
+capi_base_common_dep = dependency('capi-base-common')
+dlog_dep = dependency('dlog')
+tizen_deps = [
+  capi_base_common_dep,
+  dlog_dep
+]
+gst_app_dep = dependency('gstreamer-app-1.0')
+
+shared_library ('capi-nnstreamer',
+  capi_main,
+  dependencies: [nnstreamer_dep, glib_dep, gst_dep, gst_app_dep, tizen_deps],
+  include_directories: [
+    inc,
+    nninc
+  ],
+  install: true,
+  version: meson.project_version(),
+  install_dir: nnstreamer_libdir,
+)
+static_library ('capi-nnstreamer',
+  capi_main,
+  dependencies: [nnstreamer_dep, glib_dep, gst_dep, gst_app_dep, tizen_deps],
+  include_directories: [
+    inc,
+    nninc
+  ],
+  install: true,
+  install_dir: nnstreamer_libdir,
+)
+
+configure_file(input: 'capi-nnstreamer.pc.in', output: 'capi-nnstreamer.pc',
+  install: true,
+  install_dir: join_paths(nnstreamer_libdir, 'pkgconfig'),
+  configuration: nnstreamer_conf
+)
+
+install_headers(capi_devel_main,
+  subdir: 'nnstreamer'
+)
diff --git a/tizen-api/src/tizen-api-pipeline.c b/tizen-api/src/tizen-api-pipeline.c
new file mode 100644 (file)
index 0000000..01448e4
--- /dev/null
@@ -0,0 +1,469 @@
+/**
+ * Copyright (c) 2019 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
+ * @file tizen-api-pipeline.c
+ * @date 11 March 2019
+ * @brief Tizen NNStreamer/Pipeline(main) C-API Wrapper.
+ *        This allows to construct and control NNStreamer pipelines.
+ * @see        https://github.com/nnsuite/nnstreamer
+ * @author MyungJoo Ham <myungjoo.ham@samsung.com>
+ * @bug No known bugs except for NYI items
+ */
+
+#include <glib.h>
+#include <glib-object.h>        /* Get GType from GObject Instances */
+#include <gmodule.h>
+#include <tizen-api-private.h>
+#include <dlog.h>
+#include <nnstreamer/tensor_typedef.h>
+#include <nnstreamer/nnstreamer_plugin_api.h>
+
+/**
+ * @brief Internal function to create a refereable element in a pipeline
+ */
+static element *
+construct_element (GstElement * e, nns_pipeline * p, const char *name,
+    elementType t)
+{
+  element *ret = g_new0 (element, 1);
+  ret->element = e;
+  ret->pipe = p;
+  ret->name = g_strdup (name);
+  ret->type = t;
+  ret->handles = NULL;
+  ret->src = NULL;
+  ret->sink = NULL;
+  gst_tensors_info_init (&ret->tensorsinfo);
+  ret->size = 0;
+  g_mutex_init (&ret->lock);
+  return ret;
+}
+
+/**
+ * @brief Handle a sink element for registered nns_sink_cb
+ */
+static void
+cb_sink_event (GstElement * e, GstBuffer * b, gpointer data)
+{
+  element *elem = data;
+
+  GstMemory *mem[NNS_TENSOR_SIZE_LIMIT];
+  GstMapInfo info[NNS_TENSOR_SIZE_LIMIT];
+  guint i;
+  guint num_mems;
+  GList *l;
+  const char *buf[NNS_TENSOR_SIZE_LIMIT];
+  size_t size[NNS_TENSOR_SIZE_LIMIT];
+  size_t total_size = 0;
+
+  num_mems = gst_buffer_n_memory (b);
+
+  if (num_mems > NNS_TENSOR_SIZE_LIMIT) {
+    dlog_print (DLOG_ERROR, "nnstreamer-capi-pipeline",
+        "Number of memory chunks in a GstBuffer exceed the limit: %u > %u",
+        num_mems, NNS_TENSOR_SIZE_LIMIT);
+    return;
+  }
+
+  for (i = 0; i < num_mems; i++) {
+    mem[i] = gst_buffer_peek_memory (b, i);
+    gst_memory_map (mem[i], &info[i], GST_MAP_READ);
+    buf[i] = (const char *) info[i].data;
+    size[i] = info[i].size;
+    total_size += size[i];
+  }
+
+  g_mutex_lock (&elem->lock);
+
+  /** @todo This assumes that padcap is static */
+  if (elem->sink == NULL) {
+    /* Get the sink-pad-cap */
+    elem->sink = gst_element_get_static_pad (elem->element, "sink");
+
+    if (elem->sink) {
+      /* sinkpadcap available (negotiated) */
+      GstCaps *caps = gst_pad_get_current_caps (elem->sink);
+
+      if (caps) {
+        guint n_caps = gst_caps_get_size (caps);
+        GstTensorsConfig tconfig;
+        gboolean found = FALSE;
+
+        for (i = 0; i < n_caps; i++) {
+          GstStructure *s = gst_caps_get_structure (caps, i);
+
+          found = gst_tensors_config_from_structure (&tconfig, s);
+          if (found)
+            break;
+        }
+
+        if (found) {
+          memcpy (&elem->tensorsinfo, &tconfig.info, sizeof (GstTensorsInfo));
+          elem->size = 0;
+
+          g_assert (elem->tensorsinfo.num_tensors == num_mems);
+
+          for (i = 0; i < elem->tensorsinfo.num_tensors; i++) {
+            size_t sz = gst_tensor_info_get_size (&elem->tensorsinfo.info[i]);
+
+            g_assert (sz == size[i]);
+            elem->size += sz;
+          }
+        } else {
+          elem->sink = NULL;    /* It is not valid */
+          /** @todo What if it keeps being "NULL"? Exception handling at 2nd frame? */
+        }
+      }
+    }
+  }
+
+  g_assert (gst_buffer_get_size (b) == total_size);
+  if (elem->size > 0)
+    g_assert (gst_buffer_get_size (b) == elem->size);
+
+  /* Iterate e->handles, pass the data to them */
+  for (l = elem->handles; l != NULL; l = l->next) {
+    nns_sink *sink = l->data;
+    nns_sink_cb callback = sink->cb;
+
+    callback (buf, size, &elem->tensorsinfo, sink->pdata);
+
+    /** @todo Measure time. Warn if it takes long. Kill if it takes too long. */
+  }
+
+  g_mutex_unlock (&elem->lock);
+
+  for (i = 0; i < num_mems; i++) {
+    gst_memory_unmap (mem[i], &info[i]);
+  }
+
+  return;
+}
+
+/**
+ * @brief Construct the pipeline (more info in tizen-api.h)
+ */
+int
+nns_pipeline_construct (const char *pipeline_description, nns_pipeline_h * pipe)
+{
+  GError *err = NULL;
+  GstElement *pipeline;
+  GstIterator *it = NULL;
+  int ret = NNS_ERROR_NONE;
+
+  nns_pipeline *pipe_h;
+
+  if (FALSE == gst_init_check (NULL, NULL, &err)) {
+    if (err) {
+      dlog_print (DLOG_ERROR, "nnstreamer-capi-pipeline",
+          "Gstreamer has the following error: %s", err->message);
+      g_error_free (err);
+    } else {
+      dlog_print (DLOG_ERROR, "nnstreamer-capi-pipeline",
+          "Cannot initialize gstreamer. Unknown reason.");
+    }
+    return NNS_ERROR_PIPELINE_FAIL;
+  }
+
+  pipeline = gst_parse_launch (pipeline_description, &err);
+  if (pipeline == NULL) {
+    if (err) {
+      dlog_print (DLOG_ERROR, "nnstreamer-capi-pipeline",
+          "Cannot parse and launch the given pipeline = [%s], %s",
+          pipeline_description, err->message);
+      g_error_free (err);
+    } else {
+      dlog_print (DLOG_ERROR, "nnstreamer-capi-pipeline",
+          "Cannot parse and launch the given pipeline = [%s], unknown reason",
+          pipeline_description);
+    }
+    return NNS_ERROR_PIPELINE_FAIL;
+  }
+
+  pipe_h = g_new0 (nns_pipeline, 1);
+  *pipe = pipe_h;
+  g_assert (GST_IS_PIPELINE (pipeline));
+  pipe_h->element = pipeline;
+  g_mutex_init (&pipe_h->lock);
+  g_mutex_lock (&pipe_h->lock);
+
+  pipe_h->namednodes = g_hash_table_new (g_str_hash, g_str_equal);
+
+  it = gst_bin_iterate_elements (GST_BIN (pipeline));
+  if (it != NULL) {
+    gboolean done = FALSE;
+    GValue item = G_VALUE_INIT;
+    GObject *obj;
+    gchar *name;
+    GstElementFactory *tensor_sink = gst_element_factory_find ("tensor_sink");
+    GstElementFactory *valve = gst_element_factory_find ("valve");
+    GstElementFactory *inputs = gst_element_factory_find ("input-selector");
+    GstElementFactory *outputs = gst_element_factory_find ("output-selector");
+
+    /* Fill in the hashtable, "namednodes" with named Elements */
+    while (!done) {
+      switch (gst_iterator_next (it, &item)) {
+        case GST_ITERATOR_OK:
+          obj = g_value_get_object (&item);
+
+          if (GST_IS_ELEMENT (obj)) {
+            GstElement *elem = GST_ELEMENT (obj);
+            name = gst_element_get_name (elem);
+            if (name != NULL) {
+              element *e = NULL;
+
+              if (G_TYPE_CHECK_INSTANCE_TYPE (elem,
+                      gst_element_factory_get_element_type (tensor_sink))) {
+                e = construct_element (elem, pipe_h, name, NNSAPI_SINK);
+                g_object_set (elem, "emit-signal", (gboolean) TRUE, NULL);
+                g_signal_connect (elem, "new-data", (GCallback) cb_sink_event,
+                    e);
+              } else if (G_TYPE_CHECK_INSTANCE_TYPE (elem, GST_TYPE_APP_SRC)) {
+                e = construct_element (elem, pipe_h, name, NNSAPI_SRC);
+              } else if (G_TYPE_CHECK_INSTANCE_TYPE (elem,
+                      gst_element_factory_get_element_type (valve))) {
+                e = construct_element (elem, pipe_h, name, NNSAPI_VALVE);
+              } else if (G_TYPE_CHECK_INSTANCE_TYPE (elem,
+                      gst_element_factory_get_element_type (inputs))) {
+                e = construct_element (elem, pipe_h, name, NNSAPI_SWITCH_INPUT);
+              } else if (G_TYPE_CHECK_INSTANCE_TYPE (elem,
+                      gst_element_factory_get_element_type (outputs))) {
+                e = construct_element (elem, pipe_h, name,
+                    NNSAPI_SWITCH_OUTPUT);
+              }
+
+              if (e != NULL)
+                g_hash_table_insert (pipe_h->namednodes, e, name);
+            }
+            g_free (name);
+          }
+          g_value_reset (&item);
+
+          break;
+        case GST_ITERATOR_RESYNC:
+        case GST_ITERATOR_ERROR:
+          dlog_print (DLOG_WARN, "nnstreamer-capi-pipeline",
+              "There is an error or a resync-event while inspecting a pipeline. However, we can still execute the pipeline.");
+        case GST_ITERATOR_DONE:
+          done = TRUE;
+      }
+    }
+    g_value_unset (&item);
+    gst_iterator_free (it);
+
+    g_object_unref (tensor_sink);
+    g_object_unref (valve);
+    g_object_unref (inputs);
+    g_object_unref (outputs);
+  }
+
+  /** @todo CRITICAL: Prepare the pipeline. Maybe as a forked thread */
+
+
+  g_mutex_unlock (&pipe_h->lock);
+  return ret;
+}
+
+/**
+ * @brief Destroy the pipeline (more info in tizen-api.h)
+ */
+int
+nns_pipeline_destroy (nns_pipeline_h pipe)
+{
+  /* nns_pipeline *p = pipe; */
+
+  /** @todo NYI */
+
+  /** @todo Pause the pipeline if it's Playing */
+
+  /** @todo Ensure all callbacks are gone. (kill'em all!) */
+
+  /** @todo Stop (NULL State) the pipeline */
+
+  /** @todo Destroy Everything */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Get the pipeline state (more info in tizen-api.h)
+ */
+int
+nns_pipeline_getstate (nns_pipeline_h pipe, nns_pipeline_state * state)
+{
+  /* *state = NNSAPI_UNKNOWN; */
+
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/****************************************************
+ ** NNStreamer Pipeline Start/Stop Control         **
+ ****************************************************/
+/**
+ * @brief Start/Resume the pipeline! (more info in tizen-api.h)
+ */
+int
+nns_pipeline_start (nns_pipeline_h pipe)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Pause the pipeline! (more info in tizen-api.h)
+ */
+int
+nns_pipeline_stop (nns_pipeline_h pipe)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/****************************************************
+ ** NNStreamer Pipeline Sink/Src Control           **
+ ****************************************************/
+/**
+ * @brief Register a callback for sink (more info in tizen-api.h)
+ */
+int
+nns_pipeline_sink_register (nns_pipeline_h pipe, const char *sinkname,
+    nns_sink_cb cb, nns_sink_h * h, void *pdata)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Unregister a callback for sink (more info in tizen-api.h)
+ */
+int
+nns_pipeline_sink_unregister (nns_sink_h h)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Get a handle to operate a src (more info in tizen-api.h)
+ */
+int nns_pipeline_src_gethandle
+    (nns_pipeline_h pipe, const char *srcname, GstTensorsInfo * tensorsinfo,
+    nns_src_h * h)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Close a src node (more info in tizen-api.h)
+ */
+int
+nns_pipeline_src_puthandle (nns_src_h h)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Push a data frame to a src (more info in tizen-api.h)
+ */
+int
+nns_pipeline_src_inputdata (nns_src_h h,
+    nns_buf_policy policy, char *buf, size_t size)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/****************************************************
+ ** NNStreamer Pipeline Switch/Valve Control       **
+ ****************************************************/
+
+/**
+ * @brief Get a handle to operate a selector (more info in tizen-api.h)
+ */
+int nns_pipeline_switch_gethandle
+    (nns_pipeline_h pipe, const char *switchname, int *num_nodes,
+    nns_switch_type type, nns_switch_h * h)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Close the given switch handle (more info in tizen-api.h)
+ */
+int
+nns_pipeline_switch_puthandle (nns_switch_h h)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Control the switch (more info in tizen-api.h)
+ */
+int
+nns_pipeline_switch_select (nns_switch_h h, int node)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Get a handle to operate a Valve (more info in tizen-api.h)
+ */
+int nns_pipeline_valve_gethandle
+    (nns_pipeline_h pipe, const char *valvename, nns_valve_h * h)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Close the given valve handle (more info in tizen-api.h)
+ */
+int
+nns_pipeline_valve_puthandle (nns_valve_h h)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}
+
+/**
+ * @brief Control the valve with the given handle (more info in tizen-api.h)
+ */
+int
+nns_pipeline_valve_control (nns_valve_h h, int valve_open)
+{
+  /** @todo NYI */
+
+  return NNS_ERROR_NONE;
+}