From: Jaeyun Date: Mon, 3 Jun 2019 11:16:56 +0000 (+0900) Subject: [Tizen/Api] add appsink to handle sink event X-Git-Tag: accepted/tizen/unified/20190620.071918~25 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=69114b270c4567ceb18e4c4e66fe4747e9606041;p=platform%2Fupstream%2Fnnstreamer.git [Tizen/Api] add appsink to handle sink event 1. Register the appsink as a sink element. User can register appsink and tensor-sink as a sink element. 2. Move logging macro to private header. 3. Add testcases to test appsink element. Signed-off-by: Jaeyun Jung --- diff --git a/tests/tizen_capi/unittest_tizen_capi.cpp b/tests/tizen_capi/unittest_tizen_capi.cpp index 8cd488e..fca8ab5 100644 --- a/tests/tizen_capi/unittest_tizen_capi.cpp +++ b/tests/tizen_capi/unittest_tizen_capi.cpp @@ -404,6 +404,58 @@ TEST (nnstreamer_capi_sink, dummy_01) /** * @brief Test NNStreamer pipeline sink + */ +TEST (nnstreamer_capi_sink, dummy_02) +{ + nns_pipeline_h handle; + nns_pipeline_state_e state; + nns_sink_h sinkhandle; + gchar *pipeline; + int status; + guint *count_sink; + + /* pipeline with appsink */ + pipeline = g_strdup ("videotestsrc num-buffers=3 ! videoconvert ! valve name=valvex ! tensor_converter ! appsink name=sinkx"); + + count_sink = (guint *) g_malloc (sizeof (guint)); + *count_sink = 0; + + status = nns_pipeline_construct (pipeline, &handle); + EXPECT_EQ (status, NNS_ERROR_NONE); + + status = nns_pipeline_sink_register (handle, "sinkx", nns_sink_callback_count, &sinkhandle, count_sink); + EXPECT_EQ (status, NNS_ERROR_NONE); + + status = nns_pipeline_start (handle); + EXPECT_EQ (status, NNS_ERROR_NONE); + + g_usleep (100000); /* 100ms. Let a few frames flow. */ + status = nns_pipeline_get_state (handle, &state); + EXPECT_EQ (status, NNS_ERROR_NONE); + EXPECT_EQ (state, NNS_PIPELINE_STATE_PLAYING); + + status = nns_pipeline_stop (handle); + EXPECT_EQ (status, NNS_ERROR_NONE); + g_usleep (10000); /* 10ms. Wait a bit. */ + + status = nns_pipeline_get_state (handle, &state); + EXPECT_EQ (status, NNS_ERROR_NONE); + EXPECT_EQ (state, NNS_PIPELINE_STATE_PAUSED); + + status = nns_pipeline_sink_unregister (sinkhandle); + EXPECT_EQ (status, NNS_ERROR_NONE); + + status = nns_pipeline_destroy (handle); + EXPECT_EQ (status, NNS_ERROR_NONE); + + EXPECT_TRUE (*count_sink > 0U); + + g_free (pipeline); + g_free (count_sink); +} + +/** + * @brief Test NNStreamer pipeline sink * @detail Failure case to register callback with invalid param. */ TEST (nnstreamer_capi_sink, failure_01) diff --git a/tizen-api/include/nnstreamer.h b/tizen-api/include/nnstreamer.h index d45ae34..e6582f7 100644 --- a/tizen-api/include/nnstreamer.h +++ b/tizen-api/include/nnstreamer.h @@ -279,6 +279,7 @@ int nns_pipeline_stop (nns_pipeline_h pipe); * @param[in] pdata Private data for the callback. This value is passed to the callback when it's invoked. * @return @c 0 on success. otherwise a negative error value * @retval #NNS_ERROR_NONE Successful + * @retval #NNS_ERROR_STREAMS_PIPE Failed to connect a signal to sink element. * @retval #NNS_ERROR_INVALID_PARAMETER Given parameter is invalid. (pipe is NULL, sink_name is not found, or sink_name has an invalid type.) */ int nns_pipeline_sink_register (nns_pipeline_h pipe, const char *sink_name, nns_sink_cb cb, nns_sink_h *h, void *pdata); diff --git a/tizen-api/include/tizen-api-private.h b/tizen-api/include/tizen-api-private.h index 420e055..8f0e3ea 100644 --- a/tizen-api/include/tizen-api-private.h +++ b/tizen-api/include/tizen-api-private.h @@ -29,9 +29,21 @@ #include #include "nnstreamer.h" #include +#include #include #include +#define DLOG_TAG "nnstreamer-capi-pipeline" + +#define dlogi(...) \ + dlog_print (DLOG_INFO, DLOG_TAG, __VA_ARGS__) + +#define dlogw(...) \ + dlog_print (DLOG_WARN, DLOG_TAG, __VA_ARGS__) + +#define dloge(...) \ + dlog_print (DLOG_ERROR, DLOG_TAG, __VA_ARGS__) + #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ @@ -42,8 +54,9 @@ extern "C" { typedef enum { NNSAPI_UNKNOWN = 0x0, NNSAPI_SINK = 0x1, - NNSAPI_SRC = 0x2, - NNSAPI_VALVE = 0x3, + NNSAPI_APP_SRC = 0x2, + NNSAPI_APP_SINK = 0x3, + NNSAPI_VALVE = 0x4, NNSAPI_SWITCH_INPUT = 0x8, NNSAPI_SWITCH_OUTPUT = 0x9, } elementType; @@ -68,6 +81,7 @@ typedef struct _element { GList *handles; int maxid; /**< to allocate id for each handle */ + gulong handle_id; GMutex lock; /**< Lock for internal values */ } element; diff --git a/tizen-api/src/tizen-api-pipeline.c b/tizen-api/src/tizen-api-pipeline.c index fc876ab..b805b2c 100644 --- a/tizen-api/src/tizen-api-pipeline.c +++ b/tizen-api/src/tizen-api-pipeline.c @@ -25,24 +25,13 @@ #include /* Get GType from GObject Instances */ #include #include -#include + #include #include #include #include /* To push data to pipeline */ -#define DLOG_TAG "nnstreamer-capi-pipeline" - -#define dlogi(...) \ - dlog_print (DLOG_INFO, DLOG_TAG, __VA_ARGS__) - -#define dlogw(...) \ - dlog_print (DLOG_WARN, DLOG_TAG, __VA_ARGS__) - -#define dloge(...) \ - dlog_print (DLOG_ERROR, DLOG_TAG, __VA_ARGS__) - #define handle_init(type, name, h) \ nns_##type *name= (h); \ nns_pipeline *p; \ @@ -93,6 +82,7 @@ construct_element (GstElement * e, nns_pipeline * p, const char *name, gst_tensors_info_init (&ret->tensorsinfo); ret->size = 0; ret->maxid = 0; + ret->handle_id = 0; g_mutex_init (&ret->lock); return ret; } @@ -257,6 +247,25 @@ cb_sink_event (GstElement * e, GstBuffer * b, gpointer data) } /** + * @brief Handle a appsink element for registered nns_sink_cb + */ +static GstFlowReturn +cb_appsink_new_sample (GstElement * e, gpointer user_data) +{ + GstSample *sample; + GstBuffer *buffer; + + /* get the sample from appsink */ + sample = gst_app_sink_pull_sample (GST_APP_SINK (e)); + buffer = gst_sample_get_buffer (sample); + + cb_sink_event (e, buffer, user_data); + + gst_sample_unref (sample); + return GST_FLOW_OK; +} + +/** * @brief Private function for nns_pipeline_destroy, cleaning up nodes in namednodes */ static void @@ -360,11 +369,10 @@ nns_pipeline_construct (const char *pipeline_description, nns_pipeline_h * pipe) 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); + e = construct_element (elem, pipe_h, name, NNSAPI_APP_SRC); + } else if (G_TYPE_CHECK_INSTANCE_TYPE (elem, GST_TYPE_APP_SINK)) { + e = construct_element (elem, pipe_h, name, NNSAPI_APP_SINK); } else if (G_TYPE_CHECK_INSTANCE_TYPE (elem, gst_element_factory_get_element_type (valve))) { e = construct_element (elem, pipe_h, name, NNSAPI_VALVE); @@ -578,12 +586,42 @@ nns_pipeline_sink_register (nns_pipeline_h pipe, const char *sink_name, goto unlock_return; } - if (elem->type != NNSAPI_SINK) { - dloge ("The element [%s] in the pipeline is not a tensor_sink.", sink_name); + if (elem->type != NNSAPI_SINK && elem->type != NNSAPI_APP_SINK) { + dloge ("The element [%s] in the pipeline is not a sink element.", + sink_name); ret = NNS_ERROR_INVALID_PARAMETER; goto unlock_return; } + if (elem->handle_id > 0) { + dlogw ("Sink callback is already registered."); + ret = NNS_ERROR_NONE; + goto unlock_return; + } + + /* set callback for new data */ + if (elem->type == NNSAPI_SINK) { + /* tensor_sink */ + g_object_set (G_OBJECT (elem->element), "emit-signal", (gboolean) TRUE, + NULL); + elem->handle_id = + g_signal_connect (elem->element, "new-data", G_CALLBACK (cb_sink_event), + elem); + } else { + /* appsink */ + g_object_set (G_OBJECT (elem->element), "emit-signals", (gboolean) TRUE, + NULL); + elem->handle_id = + g_signal_connect (elem->element, "new-sample", + G_CALLBACK (cb_appsink_new_sample), elem); + } + + if (elem->handle_id == 0) { + dloge ("Failed to connect a signal to the element [%s].", sink_name); + ret = NNS_ERROR_STREAMS_PIPE; + goto unlock_return; + } + *h = g_new0 (nns_sink, 1); sink = *h; @@ -613,6 +651,11 @@ nns_pipeline_sink_unregister (nns_sink_h h) { handle_init (sink, sink, h); + if (elem->handle_id > 0) { + g_signal_handler_disconnect (elem->element, elem->handle_id); + elem->handle_id = 0; + } + elem->handles = g_list_remove (elem->handles, sink); handle_exit (h); @@ -686,8 +729,9 @@ nns_pipeline_src_get_handle (nns_pipeline_h pipe, const char *src_name, goto unlock_return; } - if (elem->type != NNSAPI_SRC) { - dloge ("The element [%s] in the pipeline is not a tensor_src.", src_name); + if (elem->type != NNSAPI_APP_SRC) { + dloge ("The element [%s] in the pipeline is not a source element.", + src_name); ret = NNS_ERROR_INVALID_PARAMETER; goto unlock_return; }