-/*
+/**
* GStreamer
* Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org>
* Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
- * Copyright (C) 2018 nnstreamer <nnstreamer sec>
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* 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_sink.c
* @date 15 June 2018
* @brief GStreamer plugin to handle tensor stream
- * @see http://github.com/TO-BE-DETERMINED-SOON
+ * @see http://github.com/nnsuite/nnstreamer
* @see https://github.sec.samsung.net/STAR/nnstreamer
* @author Jaeyun Jung <jy1210.jung@samsung.com>
* @bug No known bugs except for NYI items
GST_DEBUG_CATEGORY_STATIC (gst_tensor_sink_debug);
#define GST_CAT_DEFAULT gst_tensor_sink_debug
-/* signals and args */
+/** signals and args */
enum
{
SIGNAL_NEW_DATA,
enum
{
PROP_0,
- PROP_RENDER_RATE,
+ PROP_SIGNAL_RATE,
PROP_EMIT_SIGNAL,
PROP_SILENT
};
#define DEFAULT_EMIT_SIGNAL TRUE
/**
- * @brief Buffers rendered per second.
+ * @brief New data signals per second.
*/
-#define DEFAULT_RENDER_RATE 0
+#define DEFAULT_SIGNAL_RATE 0
/**
* @brief Flag to print minimized log.
static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_SINK,
GST_PAD_ALWAYS,
- GST_STATIC_CAPS_ANY);
+ GST_STATIC_CAPS (GST_TENSOR_CAP_DEFAULT));
/**
* @brief Variable for signal ids.
*/
static guint _tensor_sink_signals[LAST_SIGNAL] = { 0 };
-/* GObject method implementation */
+/** GObject method implementation */
static void gst_tensor_sink_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec);
static void gst_tensor_sink_get_property (GObject * object, guint prop_id,
static void gst_tensor_sink_dispose (GObject * object);
static void gst_tensor_sink_finalize (GObject * object);
-/* GstBaseSink method implementation */
+/** GstBaseSink method implementation */
static gboolean gst_tensor_sink_start (GstBaseSink * sink);
static gboolean gst_tensor_sink_stop (GstBaseSink * sink);
static gboolean gst_tensor_sink_event (GstBaseSink * sink, GstEvent * event);
static gboolean gst_tensor_sink_set_caps (GstBaseSink * sink, GstCaps * caps);
static GstCaps *gst_tensor_sink_get_caps (GstBaseSink * sink, GstCaps * filter);
-/* internal functions */
+/** internal functions */
static void _tensor_sink_render_buffer (GstTensorSink * self,
GstBuffer * buffer);
static void _tensor_sink_set_last_render_time (GstTensorSink * self,
GstClockTime now);
static GstClockTime _tensor_sink_get_last_render_time (GstTensorSink * self);
-static void _tensor_sink_set_render_rate (GstTensorSink * self, guint64 rate);
-static guint64 _tensor_sink_get_render_rate (GstTensorSink * self);
+static void _tensor_sink_set_signal_rate (GstTensorSink * self, guint rate);
+static guint _tensor_sink_get_signal_rate (GstTensorSink * self);
static void _tensor_sink_set_emit_signal (GstTensorSink * self, gboolean emit);
static gboolean _tensor_sink_get_emit_signal (GstTensorSink * self);
static void _tensor_sink_set_silent (GstTensorSink * self, gboolean silent);
static gboolean _tensor_sink_get_silent (GstTensorSink * self);
-/* functions to initialize */
-static void _tensor_sink_do_init (GType type);
+/** functions to initialize */
static gboolean _tensor_sink_plugin_init (GstPlugin * plugin);
#define gst_tensor_sink_parent_class parent_class
-G_DEFINE_TYPE_WITH_CODE (GstTensorSink, gst_tensor_sink, GST_TYPE_BASE_SINK,
- _tensor_sink_do_init (g_define_type_id));
+G_DEFINE_TYPE (GstTensorSink, gst_tensor_sink, GST_TYPE_BASE_SINK);
/**
* @brief Initialize tensor_sink class.
element_class = GST_ELEMENT_CLASS (klass);
bsink_class = GST_BASE_SINK_CLASS (klass);
- /* GObject methods */
+ /** GObject methods */
gobject_class->set_property = gst_tensor_sink_set_property;
gobject_class->get_property = gst_tensor_sink_get_property;
gobject_class->dispose = gst_tensor_sink_dispose;
gobject_class->finalize = gst_tensor_sink_finalize;
- /* properties */
- g_object_class_install_property (gobject_class, PROP_RENDER_RATE,
- g_param_spec_uint64 ("render-rate", "Render rate",
- "Buffers rendered per second (0 for unlimited, max 500)", 0, 500,
- DEFAULT_RENDER_RATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+ /** properties */
+ g_object_class_install_property (gobject_class, PROP_SIGNAL_RATE,
+ g_param_spec_uint ("signal-rate", "Signal rate",
+ "New data signals per second (0 for unlimited, max 500)", 0, 500,
+ DEFAULT_SIGNAL_RATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
g_object_class_install_property (gobject_class, PROP_EMIT_SIGNAL,
g_param_spec_boolean ("emit-signal", "Emit signal",
g_param_spec_boolean ("silent", "Silent", "Produce verbose output",
DEFAULT_SILENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
- /* signals */
+ /** signals */
_tensor_sink_signals[SIGNAL_NEW_DATA] =
g_signal_new ("new-data", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
G_STRUCT_OFFSET (GstTensorSinkClass, new_data), NULL, NULL, NULL,
gst_element_class_set_static_metadata (element_class,
"Tensor_Sink",
"Sink/Tensor",
- "Sink element to handle tensor stream", "nnstreamer <nnstreamer sec>");
+ "Sink element to handle tensor stream", "Samsung Electronics Co., Ltd.");
gst_element_class_add_static_pad_template (element_class, &sinktemplate);
- /* GstBaseSink methods */
+ /** GstBaseSink methods */
bsink_class->start = GST_DEBUG_FUNCPTR (gst_tensor_sink_start);
bsink_class->stop = GST_DEBUG_FUNCPTR (gst_tensor_sink_stop);
bsink_class->event = GST_DEBUG_FUNCPTR (gst_tensor_sink_event);
g_mutex_init (&self->mutex);
- /* init properties */
+ /** init properties */
self->silent = DEFAULT_SILENT;
self->emit_signal = DEFAULT_EMIT_SIGNAL;
- self->render_rate = DEFAULT_RENDER_RATE;
+ self->signal_rate = DEFAULT_SIGNAL_RATE;
self->last_render_time = GST_CLOCK_TIME_NONE;
self->in_caps = NULL;
- /* enable qos event */
+ /** enable qos event */
gst_base_sink_set_sync (bsink, DEFAULT_SYNC);
gst_base_sink_set_max_lateness (bsink, DEFAULT_LATENESS);
gst_base_sink_set_qos_enabled (bsink, DEFAULT_QOS);
self = GST_TENSOR_SINK (object);
switch (prop_id) {
- case PROP_RENDER_RATE:
- _tensor_sink_set_render_rate (self, g_value_get_uint64 (value));
+ case PROP_SIGNAL_RATE:
+ _tensor_sink_set_signal_rate (self, g_value_get_uint (value));
break;
case PROP_EMIT_SIGNAL:
self = GST_TENSOR_SINK (object);
switch (prop_id) {
- case PROP_RENDER_RATE:
- g_value_set_uint64 (value, _tensor_sink_get_render_rate (self));
+ case PROP_SIGNAL_RATE:
+ g_value_set_uint (value, _tensor_sink_get_signal_rate (self));
break;
case PROP_EMIT_SIGNAL:
static gboolean
gst_tensor_sink_start (GstBaseSink * sink)
{
- /* load and init resources */
+ /** load and init resources */
return TRUE;
}
static gboolean
gst_tensor_sink_stop (GstBaseSink * sink)
{
- /* free resources */
+ /** free resources */
return TRUE;
}
switch (type) {
case GST_QUERY_SEEKING:
DLOG ("query SEEKING");
- /* tensor sink does not support seeking */
+ /** tensor sink does not support seeking */
gst_query_parse_seeking (query, &format, NULL, NULL, NULL);
gst_query_set_seeking (query, format, FALSE, 0, -1);
return TRUE;
_tensor_sink_render_buffer (GstTensorSink * self, GstBuffer * buffer)
{
GstClockTime now = GST_CLOCK_TIME_NONE;
- guint64 render_rate;
+ guint signal_rate;
gboolean notify = FALSE;
g_return_if_fail (GST_IS_TENSOR_SINK (self));
- render_rate = _tensor_sink_get_render_rate (self);
+ signal_rate = _tensor_sink_get_signal_rate (self);
- if (render_rate) {
+ if (signal_rate) {
GstClock *clock;
GstClockTime render_time;
GstClockTime last_render_time;
now = gst_clock_get_time (clock);
last_render_time = _tensor_sink_get_last_render_time (self);
- /* time for next render */
- render_time = (1000 / render_rate) * GST_MSECOND + last_render_time;
+ /** time for next signal */
+ render_time = (1000 / signal_rate) * GST_MSECOND + last_render_time;
if (!GST_CLOCK_TIME_IS_VALID (last_render_time) ||
GST_CLOCK_DIFF (now, render_time) <= 0) {
- /* send data after render time, or firstly received buffer */
+ /** send data after render time, or firstly received buffer */
notify = TRUE;
}
gst_object_unref (clock);
}
} else {
- /* send data if render rate is 0 */
+ /** send data if signal rate is 0 */
notify = TRUE;
}
_tensor_sink_set_last_render_time (self, now);
if (_tensor_sink_get_emit_signal (self)) {
- DLOG ("signal for new data [%" GST_TIME_FORMAT "], rate [%ld]",
- GST_TIME_ARGS (now), render_rate);
+ DLOG ("signal for new data [%" GST_TIME_FORMAT "], rate [%d]",
+ GST_TIME_ARGS (now), signal_rate);
g_signal_emit (self, _tensor_sink_signals[SIGNAL_NEW_DATA], 0, buffer);
}
}
}
/**
- * @brief Setter for value render_rate.
+ * @brief Setter for value signal_rate.
*/
static void
-_tensor_sink_set_render_rate (GstTensorSink * self, guint64 rate)
+_tensor_sink_set_signal_rate (GstTensorSink * self, guint rate)
{
g_return_if_fail (GST_IS_TENSOR_SINK (self));
- DLOG ("set render_rate to %ld", rate);
+ DLOG ("set signal_rate to %d", rate);
g_mutex_lock (&self->mutex);
- self->render_rate = rate;
+ self->signal_rate = rate;
g_mutex_unlock (&self->mutex);
}
/**
- * @brief Getter for value render_rate.
+ * @brief Getter for value signal_rate.
*/
-static guint64
-_tensor_sink_get_render_rate (GstTensorSink * self)
+static guint
+_tensor_sink_get_signal_rate (GstTensorSink * self)
{
- guint64 rate;
+ guint rate;
g_return_val_if_fail (GST_IS_TENSOR_SINK (self), 0);
g_mutex_lock (&self->mutex);
- rate = self->render_rate;
+ rate = self->signal_rate;
g_mutex_unlock (&self->mutex);
return rate;
}
/**
- * @brief Function used in type implementation.
- */
-static void
-_tensor_sink_do_init (GType type)
-{
- /* add interface */
-}
-
-/**
* @brief Function to initialize the plugin.
*
* See GstPluginInitFunc() for more details.
* GStreamer
* Copyright (C) 2005 Thomas Vander Stichele <thomas@apestaart.org>
* Copyright (C) 2005 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
- * Copyright (C) 2018 nnstreamer <nnstreamer sec>
+ * Copyright (C) 2018 Samsung Electronics Co., Ltd.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* 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_sink.h
* @date 15 June 2018
* @brief GStreamer plugin to handle tensor stream
- * @see http://github.com/TO-BE-DETERMINED-SOON
+ * @see http://github.com/nnsuite/nnstreamer
* @see https://github.sec.samsung.net/STAR/nnstreamer
* @author Jaeyun Jung <jy1210.jung@samsung.com>
* @bug No known bugs except for NYI items
GMutex mutex; /**< mutex for processing */
gboolean silent; /**< true to print minimized log */
gboolean emit_signal; /**< true to emit signal for new data, eos */
- guint64 render_rate; /**< buffers rendered per second */
+ guint signal_rate; /**< new data signals per second */
GstClockTime last_render_time; /**< buffer rendered time */
GstCaps *in_caps; /**< received caps */
};
{
GstBaseSinkClass parent_class; /**< parent class */
- /* signals */
+ /** signals */
void (*new_data) (GstElement * element, GstBuffer * buffer); /**< signal when new data received */
void (*stream_start) (GstElement * element); /**< signal when stream started */
void (*eos) (GstElement * element); /**< signal when end of stream reached */
G_END_DECLS
-#endif /* __GST_TENSOR_SINK_H__ */
+#endif /** __GST_TENSOR_SINK_H__ */
gchar *debug;
GError *error;
+ g_return_if_fail (message != NULL);
+
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error (message, &error, &debug);
_print_log ("start app..");
- /* check cam */
+ /** check cam */
_check_cond_err (_check_cam_device (cam_dev));
- /* init gstreamer */
+ /** init gstreamer */
gst_init (&argc, &argv);
- /* main loop */
+ /** main loop */
g_app.loop = g_main_loop_new (NULL, FALSE);
_check_cond_err (g_app.loop != NULL);
- /* init data pipeline */
+ /** init data pipeline */
str_pipeline =
g_strdup_printf
("v4l2src name=cam_src ! "
g_free (str_pipeline);
_check_cond_err (g_app.pipeline != NULL);
- /* data message callback */
+ /** data message callback */
g_app.bus = gst_element_get_bus (g_app.pipeline);
_check_cond_err (g_app.bus != NULL);
(GCallback) _message_cb, NULL);
_check_cond_err (handle_id > 0);
- /* start pipeline */
+ /** start pipeline */
gst_element_set_state (g_app.pipeline, GST_STATE_PLAYING);
- /* set window title */
+ /** set window title */
element = gst_bin_get_by_name (GST_BIN (g_app.pipeline), "img_mixed");
_set_window_title (element, "Mixed");
gst_object_unref (element);
_set_window_title (element, "Original");
gst_object_unref (element);
- /* run main loop */
+ /** run main loop */
g_main_loop_run (g_app.loop);
+ /** quit when received eos or error message */
- /* cam source element */
+ /** cam source element */
element = gst_bin_get_by_name (GST_BIN (g_app.pipeline), "cam_src");
- /* quit when received eos or error message */
gst_element_set_state (element, GST_STATE_READY);
gst_element_set_state (g_app.pipeline, GST_STATE_READY);
GMainLoop *loop; /**< main event loop */
GstElement *pipeline; /**< gst pipeline for test */
GstBus *bus; /**< gst bus for test */
- GstElement *sink; /**< tensor sink element */
guint received; /**< received buffer count */
} AppData;
/**
* @brief Data for pipeline and result.
*/
-static AppData g_app_data;
+static AppData g_app;
/**
* @brief Free resources in app data.
static void
_free_app_data (void)
{
- if (g_app_data.loop) {
- g_main_loop_unref (g_app_data.loop);
- g_app_data.loop = NULL;
+ if (g_app.loop) {
+ g_main_loop_unref (g_app.loop);
+ g_app.loop = NULL;
}
- if (g_app_data.bus) {
- gst_bus_remove_signal_watch (g_app_data.bus);
- gst_object_unref (g_app_data.bus);
- g_app_data.bus = NULL;
+ if (g_app.bus) {
+ gst_bus_remove_signal_watch (g_app.bus);
+ gst_object_unref (g_app.bus);
+ g_app.bus = NULL;
}
- if (g_app_data.sink) {
- gst_object_unref (g_app_data.sink);
- g_app_data.sink = NULL;
- }
-
- if (g_app_data.pipeline) {
- gst_object_unref (g_app_data.pipeline);
- g_app_data.pipeline = NULL;
+ if (g_app.pipeline) {
+ gst_object_unref (g_app.pipeline);
+ g_app.pipeline = NULL;
}
}
gchar *debug;
GError *error;
+ g_return_if_fail (message != NULL);
+
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error (message, &error, &debug);
}
/**
+ * @brief Function to print caps.
+ */
+static void
+_parse_caps (GstCaps * caps)
+{
+ guint caps_size, i;
+
+ g_return_if_fail (caps != NULL);
+
+ caps_size = gst_caps_get_size (caps);
+
+ for (i = 0; i < caps_size; i++) {
+ GstStructure *structure = gst_caps_get_structure (caps, i);
+ gchar *str = gst_structure_to_string (structure);
+
+ _print_log ("[%d] %s", i, str);
+ g_free (str);
+ }
+}
+
+/**
* @brief Callback for message.
*/
static void
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_EOS:
_print_log ("received eos message");
- g_main_loop_quit (g_app_data.loop);
+ g_main_loop_quit (g_app.loop);
break;
case GST_MESSAGE_ERROR:
_print_log ("received error message");
_parse_err_message (message);
- g_main_loop_quit (g_app_data.loop);
+ g_main_loop_quit (g_app.loop);
break;
case GST_MESSAGE_WARNING:
static void
_new_data_cb (GstElement * element, GstBuffer * buffer, gpointer user_data)
{
- g_app_data.received++;
- _print_log ("new data callback [%d]", g_app_data.received);
+ g_app.received++;
+ if (g_app.received % 150 == 0) {
+ _print_log ("receiving new data [%d]", g_app.received);
+ }
- /* example to get data */
- if (DBG) {
+ /** example to get data */
+ {
GstMemory *mem;
GstMapInfo info;
guint i;
mem = gst_buffer_peek_memory (buffer, i);
if (gst_memory_map (mem, &info, GST_MAP_READ)) {
- /* check data (info.data, info.size) */
+ /** check data (info.data, info.size) */
_print_log ("received %zd", info.size);
gst_memory_unmap (mem, &info);
}
}
- /* example to get negotiated caps */
- if (DBG) {
+ /** example to get caps */
+ {
GstPad *sink_pad;
GstCaps *caps;
- sink_pad = gst_element_get_static_pad (g_app_data.sink, "sink");
+ sink_pad = gst_element_get_static_pad (element, "sink");
if (sink_pad) {
+ /** negotiated */
caps = gst_pad_get_current_caps (sink_pad);
if (caps) {
- guint caps_size, i;
-
- caps_size = gst_caps_get_size (caps);
- _print_log ("caps size is %d", caps_size);
-
- for (i = 0; i < caps_size; i++) {
- GstStructure *structure = gst_caps_get_structure (caps, i);
- gchar *str = gst_structure_to_string (structure);
+ _parse_caps (caps);
+ gst_caps_unref (caps);
+ }
- _print_log ("[%d] %s", i, str);
- g_free (str);
- }
+ /** template */
+ caps = gst_pad_get_pad_template_caps (sink_pad);
+ if (caps) {
+ _parse_caps (caps);
gst_caps_unref (caps);
}
gchar *str_pipeline;
gulong handle_id;
GstStateChangeReturn state_ret;
+ GstElement *element;
- /* init gstreamer */
+ /** init gstreamer */
gst_init (&argc, &argv);
- /* init app variable */
- g_app_data.received = 0;
+ /** init app variable */
+ g_app.received = 0;
- /* main loop and pipeline */
- g_app_data.loop = g_main_loop_new (NULL, FALSE);
- _check_cond_err (g_app_data.loop != NULL);
+ /** main loop and pipeline */
+ g_app.loop = g_main_loop_new (NULL, FALSE);
+ _check_cond_err (g_app.loop != NULL);
- /* 640x480 30fps for test */
+ /** 640x480 30fps for test */
str_pipeline =
g_strdup_printf
("videotestsrc num-buffers=%d ! video/x-raw,format=RGB,width=%d,height=%d ! "
"tensor_converter ! tensor_sink name=tensor_sink",
num_buffers, width, height);
- g_app_data.pipeline = gst_parse_launch (str_pipeline, NULL);
+ g_app.pipeline = gst_parse_launch (str_pipeline, NULL);
g_free (str_pipeline);
- _check_cond_err (g_app_data.pipeline != NULL);
+ _check_cond_err (g_app.pipeline != NULL);
- /* message callback */
- g_app_data.bus = gst_element_get_bus (g_app_data.pipeline);
- _check_cond_err (g_app_data.bus != NULL);
+ /** message callback */
+ g_app.bus = gst_element_get_bus (g_app.pipeline);
+ _check_cond_err (g_app.bus != NULL);
- gst_bus_add_signal_watch (g_app_data.bus);
- handle_id = g_signal_connect (g_app_data.bus, "message",
+ gst_bus_add_signal_watch (g_app.bus);
+ handle_id = g_signal_connect (g_app.bus, "message",
(GCallback) _message_cb, NULL);
_check_cond_err (handle_id > 0);
- /* get tensor sink element using name */
- g_app_data.sink =
- gst_bin_get_by_name (GST_BIN (g_app_data.pipeline), "tensor_sink");
- _check_cond_err (g_app_data.sink != NULL);
+ /** get tensor sink element using name */
+ element = gst_bin_get_by_name (GST_BIN (g_app.pipeline), "tensor_sink");
+ _check_cond_err (element != NULL);
if (DBG) {
- /* print logs, default TRUE */
- g_object_set (g_app_data.sink, "silent", (gboolean) FALSE, NULL);
+ /** print logs, default TRUE */
+ g_object_set (element, "silent", (gboolean) FALSE, NULL);
}
- /* enable emit-signal, default TRUE */
- g_object_set (g_app_data.sink, "emit-signal", (gboolean) TRUE, NULL);
+ /** enable emit-signal, default TRUE */
+ g_object_set (element, "emit-signal", (gboolean) TRUE, NULL);
- /* tensor sink signal : new data callback */
- handle_id = g_signal_connect (g_app_data.sink, "new-data",
+ /** tensor sink signal : new data callback */
+ handle_id = g_signal_connect (element, "new-data",
(GCallback) _new_data_cb, NULL);
_check_cond_err (handle_id > 0);
- /* tensor sink signal : stream-start callback, optional */
- handle_id = g_signal_connect (g_app_data.sink, "stream-start",
+ /** tensor sink signal : stream-start callback, optional */
+ handle_id = g_signal_connect (element, "stream-start",
(GCallback) _stream_start_cb, NULL);
_check_cond_err (handle_id > 0);
- /* tensor sink signal : eos callback, optional */
- handle_id = g_signal_connect (g_app_data.sink, "eos",
- (GCallback) _eos_cb, NULL);
+ /** tensor sink signal : eos callback, optional */
+ handle_id = g_signal_connect (element, "eos", (GCallback) _eos_cb, NULL);
_check_cond_err (handle_id > 0);
- /* start pipeline */
- state_ret = gst_element_set_state (g_app_data.pipeline, GST_STATE_PLAYING);
+ gst_object_unref (element);
+
+ /** start pipeline */
+ state_ret = gst_element_set_state (g_app.pipeline, GST_STATE_PLAYING);
_check_cond_err (state_ret != GST_STATE_CHANGE_FAILURE);
- g_main_loop_run (g_app_data.loop);
+ /** run main loop */
+ g_main_loop_run (g_app.loop);
+ /** quit when received eos message */
- /* quit when received eos message */
- state_ret = gst_element_set_state (g_app_data.pipeline, GST_STATE_NULL);
+ state_ret = gst_element_set_state (g_app.pipeline, GST_STATE_NULL);
_check_cond_err (state_ret != GST_STATE_CHANGE_FAILURE);
- _print_log ("total received %d", g_app_data.received);
+ _print_log ("total received %d", g_app.received);
error:
_free_app_data ();
GstBus *data_bus; /**< gst bus for data pipeline */
GstElement *player_pipeline; /**< gst pipeline for player */
GstBus *player_bus; /**< gst bus for player pipeline */
- GstElement *tensor_sink; /**< tensor sink element */
- GstElement *player_src; /**< player source element */
- guint received; /**< received buffer count */
gboolean set_caps; /**< caps passed to player pipeline */
+ guint received; /**< received buffer count */
} AppData;
/**
* @brief Data for pipeline and result.
*/
-static AppData g_app_data;
+static AppData g_app;
/**
* @brief Free resources in app data.
static void
_free_app_data (void)
{
- if (g_app_data.loop) {
- g_main_loop_unref (g_app_data.loop);
- g_app_data.loop = NULL;
- }
-
- if (g_app_data.data_bus) {
- gst_bus_remove_signal_watch (g_app_data.data_bus);
- gst_object_unref (g_app_data.data_bus);
- g_app_data.data_bus = NULL;
+ if (g_app.loop) {
+ g_main_loop_unref (g_app.loop);
+ g_app.loop = NULL;
}
- if (g_app_data.player_bus) {
- gst_bus_remove_signal_watch (g_app_data.player_bus);
- gst_object_unref (g_app_data.player_bus);
- g_app_data.player_bus = NULL;
+ if (g_app.data_bus) {
+ gst_bus_remove_signal_watch (g_app.data_bus);
+ gst_object_unref (g_app.data_bus);
+ g_app.data_bus = NULL;
}
- if (g_app_data.tensor_sink) {
- gst_object_unref (g_app_data.tensor_sink);
- g_app_data.tensor_sink = NULL;
+ if (g_app.player_bus) {
+ gst_bus_remove_signal_watch (g_app.player_bus);
+ gst_object_unref (g_app.player_bus);
+ g_app.player_bus = NULL;
}
- if (g_app_data.player_src) {
- gst_object_unref (g_app_data.player_src);
- g_app_data.player_src = NULL;
+ if (g_app.data_pipeline) {
+ gst_object_unref (g_app.data_pipeline);
+ g_app.data_pipeline = NULL;
}
- if (g_app_data.data_pipeline) {
- gst_object_unref (g_app_data.data_pipeline);
- g_app_data.data_pipeline = NULL;
- }
-
- if (g_app_data.player_pipeline) {
- gst_object_unref (g_app_data.player_pipeline);
- g_app_data.player_pipeline = NULL;
+ if (g_app.player_pipeline) {
+ gst_object_unref (g_app.player_pipeline);
+ g_app.player_pipeline = NULL;
}
}
gchar *debug;
GError *error;
+ g_return_if_fail (message != NULL);
+
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_ERROR:
gst_message_parse_error (message, &error, &debug);
static void
_data_message_cb (GstBus * bus, GstMessage * message, gpointer user_data)
{
+ GstElement *player_src;
+
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_EOS:
_print_log ("[data] received eos message");
- gst_app_src_end_of_stream (GST_APP_SRC (g_app_data.player_src));
+ player_src = gst_bin_get_by_name (GST_BIN (g_app.player_pipeline),
+ "player_src");
+ gst_app_src_end_of_stream (GST_APP_SRC (player_src));
+ gst_object_unref (player_src);
break;
case GST_MESSAGE_ERROR:
_print_log ("[data] received error message");
_parse_err_message (message);
- g_main_loop_quit (g_app_data.loop);
+ g_main_loop_quit (g_app.loop);
break;
case GST_MESSAGE_WARNING:
switch (GST_MESSAGE_TYPE (message)) {
case GST_MESSAGE_EOS:
_print_log ("[player] received eos message");
- g_main_loop_quit (g_app_data.loop);
+ g_main_loop_quit (g_app.loop);
break;
case GST_MESSAGE_ERROR:
_print_log ("[player] received error message");
_parse_err_message (message);
- g_main_loop_quit (g_app_data.loop);
+ g_main_loop_quit (g_app.loop);
break;
case GST_MESSAGE_WARNING:
static void
_new_data_cb (GstElement * element, GstBuffer * buffer, gpointer user_data)
{
- g_app_data.received++;
- _print_log ("new data callback [%d]", g_app_data.received);
+ GstElement *player_src;
+
+ g_app.received++;
+ if (g_app.received % 150 == 0) {
+ _print_log ("receiving new data [%d]", g_app.received);
+ }
- if (!g_app_data.set_caps) {
+ player_src =
+ gst_bin_get_by_name (GST_BIN (g_app.player_pipeline), "player_src");
+
+ if (!g_app.set_caps) {
GstPad *sink_pad;
GstCaps *caps;
- sink_pad = gst_element_get_static_pad (g_app_data.tensor_sink, "sink");
+ sink_pad = gst_element_get_static_pad (element, "sink");
if (sink_pad) {
caps = gst_pad_get_current_caps (sink_pad);
if (caps) {
- gst_app_src_set_caps (GST_APP_SRC (g_app_data.player_src), caps);
+ gst_app_src_set_caps (GST_APP_SRC (player_src), caps);
gst_caps_unref (caps);
- g_app_data.set_caps = TRUE;
+ g_app.set_caps = TRUE;
}
gst_object_unref (sink_pad);
}
}
- gst_app_src_push_buffer (GST_APP_SRC (g_app_data.player_src),
- gst_buffer_copy (buffer));
+ gst_app_src_push_buffer (GST_APP_SRC (player_src), gst_buffer_copy (buffer));
+ gst_object_unref (player_src);
}
/**
gchar *str_pipeline;
gulong handle_id;
+ GstElement *element;
- /* init gstreamer */
+ /** init gstreamer */
gst_init (&argc, &argv);
- /* init app variable */
- g_app_data.received = 0;
- g_app_data.set_caps = FALSE;
+ /** init app variable */
+ g_app.set_caps = FALSE;
+ g_app.received = 0;
- /* main loop and pipeline */
- g_app_data.loop = g_main_loop_new (NULL, FALSE);
- _check_cond_err (g_app_data.loop != NULL);
+ /** main loop and pipeline */
+ g_app.loop = g_main_loop_new (NULL, FALSE);
+ _check_cond_err (g_app.loop != NULL);
str_pipeline =
g_strdup_printf
("videotestsrc is-live=TRUE ! video/x-raw,format=RGB,width=%d,height=%d ! "
"tensor_converter ! tensor_sink name=tensor_sink", width, height);
- g_app_data.data_pipeline = gst_parse_launch (str_pipeline, NULL);
+ g_app.data_pipeline = gst_parse_launch (str_pipeline, NULL);
g_free (str_pipeline);
- _check_cond_err (g_app_data.data_pipeline != NULL);
+ _check_cond_err (g_app.data_pipeline != NULL);
- /* data message callback */
- g_app_data.data_bus = gst_element_get_bus (g_app_data.data_pipeline);
- _check_cond_err (g_app_data.data_bus != NULL);
+ /** data message callback */
+ g_app.data_bus = gst_element_get_bus (g_app.data_pipeline);
+ _check_cond_err (g_app.data_bus != NULL);
- gst_bus_add_signal_watch (g_app_data.data_bus);
- handle_id = g_signal_connect (g_app_data.data_bus, "message",
+ gst_bus_add_signal_watch (g_app.data_bus);
+ handle_id = g_signal_connect (g_app.data_bus, "message",
(GCallback) _data_message_cb, NULL);
_check_cond_err (handle_id > 0);
- /* get tensor sink element using name */
- g_app_data.tensor_sink =
- gst_bin_get_by_name (GST_BIN (g_app_data.data_pipeline), "tensor_sink");
- _check_cond_err (g_app_data.tensor_sink != NULL);
+ /** get tensor sink element using name */
+ element = gst_bin_get_by_name (GST_BIN (g_app.data_pipeline), "tensor_sink");
+ _check_cond_err (element != NULL);
if (DBG) {
- /* print logs, default TRUE */
- g_object_set (g_app_data.tensor_sink, "silent", (gboolean) FALSE, NULL);
+ /** print logs, default TRUE */
+ g_object_set (element, "silent", (gboolean) FALSE, NULL);
}
- /* enable emit-signal, default TRUE */
- g_object_set (g_app_data.tensor_sink, "emit-signal", (gboolean) TRUE, NULL);
+ /** enable emit-signal, default TRUE */
+ g_object_set (element, "emit-signal", (gboolean) TRUE, NULL);
- /* tensor sink signal : new data callback */
- handle_id = g_signal_connect (g_app_data.tensor_sink, "new-data",
+ /** tensor sink signal : new data callback */
+ handle_id = g_signal_connect (element, "new-data",
(GCallback) _new_data_cb, NULL);
_check_cond_err (handle_id > 0);
- /* init player pipeline */
+ gst_object_unref (element);
+
+ /** init player pipeline */
str_pipeline =
g_strdup_printf
("appsrc name=player_src ! tensordec ! videoconvert ! xvimagesink");
- g_app_data.player_pipeline = gst_parse_launch (str_pipeline, NULL);
+ g_app.player_pipeline = gst_parse_launch (str_pipeline, NULL);
g_free (str_pipeline);
- _check_cond_err (g_app_data.player_pipeline != NULL);
+ _check_cond_err (g_app.player_pipeline != NULL);
- /* player message callback */
- g_app_data.player_bus = gst_element_get_bus (g_app_data.player_pipeline);
- _check_cond_err (g_app_data.player_bus != NULL);
+ /** player message callback */
+ g_app.player_bus = gst_element_get_bus (g_app.player_pipeline);
+ _check_cond_err (g_app.player_bus != NULL);
- gst_bus_add_signal_watch (g_app_data.player_bus);
- handle_id = g_signal_connect (g_app_data.player_bus, "message",
+ gst_bus_add_signal_watch (g_app.player_bus);
+ handle_id = g_signal_connect (g_app.player_bus, "message",
(GCallback) _player_message_cb, NULL);
_check_cond_err (handle_id > 0);
- /* player source element */
- g_app_data.player_src =
- gst_bin_get_by_name (GST_BIN (g_app_data.player_pipeline), "player_src");
- _check_cond_err (g_app_data.player_src != NULL);
-
- /* start pipeline */
- gst_element_set_state (g_app_data.data_pipeline, GST_STATE_PLAYING);
- gst_element_set_state (g_app_data.player_pipeline, GST_STATE_PLAYING);
+ /** start pipeline */
+ gst_element_set_state (g_app.data_pipeline, GST_STATE_PLAYING);
+ gst_element_set_state (g_app.player_pipeline, GST_STATE_PLAYING);
- g_main_loop_run (g_app_data.loop);
+ /** run main loop */
+ g_main_loop_run (g_app.loop);
+ /** quit when received eos message */
- /* quit when received eos message */
- gst_element_set_state (g_app_data.data_pipeline, GST_STATE_NULL);
- gst_element_set_state (g_app_data.player_pipeline, GST_STATE_NULL);
+ gst_element_set_state (g_app.data_pipeline, GST_STATE_NULL);
+ gst_element_set_state (g_app.player_pipeline, GST_STATE_NULL);
error:
_free_app_data ();
* @see http://github.com/TO-BE-DETERMINED-SOON
* @see https://github.sec.samsung.net/STAR/nnstreamer
* @author Jaeyun Jung <jy1210.jung@samsung.com>
+ * @bug No known bugs.
*/
#include <gtest/gtest.h>
{
g_test_data.received++;
_print_log ("new data callback [%d]", g_test_data.received);
-
- /* example to get data */
- if (DBG) {
- GstMemory *mem;
- GstMapInfo info;
- guint i;
- guint num_mems;
-
- num_mems = gst_buffer_n_memory (buffer);
- for (i = 0; i < num_mems; i++) {
- mem = gst_buffer_peek_memory (buffer, i);
-
- if (gst_memory_map (mem, &info, GST_MAP_READ)) {
- /* check data (info.data, info.size) */
- _print_log ("received %zd", info.size);
-
- gst_memory_unmap (mem, &info);
- }
- }
- }
-
- /* example to get negotiated caps */
- if (DBG) {
- GstPad *sink_pad;
- GstCaps *caps;
-
- sink_pad = gst_element_get_static_pad (g_test_data.sink, "sink");
-
- if (sink_pad) {
- g_object_get (sink_pad, "caps", &caps, NULL);
-
- if (caps) {
- guint caps_size, i;
-
- caps_size = gst_caps_get_size (caps);
- _print_log ("caps size is %d", caps_size);
-
- for (i = 0; i < caps_size; i++) {
- GstStructure *structure = gst_caps_get_structure (caps, i);
- gchar *str = gst_structure_to_string (structure);
-
- _print_log ("[%d] %s", i, str);
- g_free (str);
- }
-
- gst_caps_unref (caps);
- }
-
- gst_object_unref (sink_pad);
- }
- }
}
/**
str_pipeline =
g_strdup_printf
- ("videotestsrc num-buffers=%d ! video/x-raw,width=640,height=480,framerate=(fraction)30/1 ! videoconvert ! video/x-raw,format=RGB ! tensor_converter ! tensor_sink name=test_sink",
- num_buffers);
+ ("videotestsrc num-buffers=%d ! video/x-raw,width=160,height=120,format=RGB,framerate=(fraction)30/1 ! "
+ "tensor_converter ! tensor_sink name=test_sink", num_buffers);
g_test_data.pipeline = gst_parse_launch (str_pipeline, NULL);
g_free (str_pipeline);
_check_cond_err (g_test_data.pipeline != NULL);
*/
TEST (tensor_sink_test, properties)
{
- guint64 rate, res_rate;
+ guint rate, res_rate;
gint64 lateness, res_lateness;
gboolean silent, res_silent;
gboolean emit, res_emit;
ASSERT_TRUE (_setup_pipeline (1));
- /* default render-rate is 0 */
- g_object_get (g_test_data.sink, "render-rate", &rate, NULL);
+ /** default signal-rate is 0 */
+ g_object_get (g_test_data.sink, "signal-rate", &rate, NULL);
EXPECT_EQ (rate, 0);
- g_object_set (g_test_data.sink, "render-rate", (rate + 10), NULL);
- g_object_get (g_test_data.sink, "render-rate", &res_rate, NULL);
+ g_object_set (g_test_data.sink, "signal-rate", (rate + 10), NULL);
+ g_object_get (g_test_data.sink, "signal-rate", &res_rate, NULL);
EXPECT_EQ (res_rate, (rate + 10));
- /* default emit-signal is TRUE */
+ /** default emit-signal is TRUE */
g_object_get (g_test_data.sink, "emit-signal", &emit, NULL);
EXPECT_EQ (emit, TRUE);
g_object_get (g_test_data.sink, "emit-signal", &res_emit, NULL);
EXPECT_EQ (res_emit, !emit);
- /* default silent is TRUE */
+ /** default silent is TRUE */
g_object_get (g_test_data.sink, "silent", &silent, NULL);
EXPECT_EQ (silent, TRUE);
g_object_get (g_test_data.sink, "silent", &res_silent, NULL);
EXPECT_EQ (res_silent, !silent);
- /* GstBaseSink:sync TRUE */
+ /** GstBaseSink:sync TRUE */
g_object_get (g_test_data.sink, "sync", &sync, NULL);
EXPECT_EQ (sync, TRUE);
g_object_get (g_test_data.sink, "sync", &res_sync, NULL);
EXPECT_EQ (res_sync, !sync);
- /* GstBaseSink:max-lateness 30ms */
+ /** GstBaseSink:max-lateness 30ms */
g_object_get (g_test_data.sink, "max-lateness", &lateness, NULL);
EXPECT_EQ (lateness, (30 * GST_MSECOND));
- /* -1 means unlimited time */
+ /** -1 means unlimited time */
g_object_set (g_test_data.sink, "max-lateness", (gint64) (-1), NULL);
g_object_get (g_test_data.sink, "max-lateness", &res_lateness, NULL);
EXPECT_EQ (res_lateness, -1);
- /* GstBaseSink:qos TRUE */
+ /** GstBaseSink:qos TRUE */
g_object_get (g_test_data.sink, "qos", &qos, NULL);
EXPECT_EQ (qos, TRUE);
ASSERT_TRUE (_setup_pipeline (num_buffers));
if (DBG) {
- /* print logs */
- g_object_set (g_test_data.sink, "silent", FALSE, NULL);
+ /** print logs */
+ g_object_set (g_test_data.sink, "silent", (gboolean) FALSE, NULL);
}
- /* enable emit-signal */
- g_object_set (g_test_data.sink, "emit-signal", TRUE, NULL);
-
- /* tensor sink signals */
+ /** tensor sink signals */
handle_id = g_signal_connect (g_test_data.sink, "new-data",
(GCallback) _new_data_cb, NULL);
EXPECT_TRUE (handle_id > 0);
g_main_loop_run (g_test_data.loop);
gst_element_set_state (g_test_data.pipeline, GST_STATE_NULL);
- /* check eos message */
+ /** check eos message */
EXPECT_EQ (g_test_data.status, TEST_EOS);
- /* check received buffers and signals */
+ /** check received buffers and signals */
EXPECT_EQ (g_test_data.received, num_buffers);
EXPECT_EQ (g_test_data.start, TRUE);
EXPECT_EQ (g_test_data.end, TRUE);
}
/**
- * @brief Test for tensor sink render-rate.
+ * @brief Test for tensor sink signal-rate.
*/
-TEST (tensor_sink_test, render_rate)
+TEST (tensor_sink_test, signal_rate)
{
const guint num_buffers = 10;
gulong handle_id;
ASSERT_TRUE (_setup_pipeline (num_buffers));
if (DBG) {
- /* print logs */
- g_object_set (g_test_data.sink, "silent", FALSE, NULL);
+ /** print logs */
+ g_object_set (g_test_data.sink, "silent", (gboolean) FALSE, NULL);
}
- /* enable emit-signal */
- g_object_set (g_test_data.sink, "emit-signal", TRUE, NULL);
+ /** set signal-rate */
+ g_object_set (g_test_data.sink, "signal-rate", (guint) 15, NULL);
- /* set render-rate */
- g_object_set (g_test_data.sink, "render-rate", (guint64) 15, NULL);
-
- /* signal for new data */
+ /** signal for new data */
handle_id = g_signal_connect (g_test_data.sink, "new-data",
(GCallback) _new_data_cb, NULL);
EXPECT_TRUE (handle_id > 0);
- _print_log ("start pipeline for render-rate test");
+ _print_log ("start pipeline for signal-rate test");
gst_element_set_state (g_test_data.pipeline, GST_STATE_PLAYING);
g_main_loop_run (g_test_data.loop);
gst_element_set_state (g_test_data.pipeline, GST_STATE_NULL);
- /* check eos message */
+ /** check eos message */
EXPECT_EQ (g_test_data.status, TEST_EOS);
- /* check received buffers */
+ /** check received buffers */
EXPECT_TRUE (g_test_data.received < num_buffers);
_free_test_data ();
ASSERT_TRUE (_setup_pipeline (num_buffers));
if (DBG) {
- /* print logs */
- g_object_set (g_test_data.sink, "silent", FALSE, NULL);
+ /** print logs */
+ g_object_set (g_test_data.sink, "silent", (gboolean) FALSE, NULL);
}
- /* try to set/get unknown property */
+ /** try to set/get unknown property */
g_object_set (g_test_data.sink, "unknown-prop", 1, NULL);
g_object_get (g_test_data.sink, "unknown-prop", &unknown, NULL);
EXPECT_EQ (unknown, -1);
- /* unknown signal */
+ /** unknown signal */
handle_id = g_signal_connect (g_test_data.sink, "unknown-sig",
(GCallback) _new_data_cb, NULL);
EXPECT_EQ (handle_id, 0);
g_main_loop_run (g_test_data.loop);
gst_element_set_state (g_test_data.pipeline, GST_STATE_NULL);
- /* check eos message */
+ /** check eos message */
EXPECT_EQ (g_test_data.status, TEST_EOS);
- /* check received buffers */
+ /** check received buffers */
+ EXPECT_EQ (g_test_data.received, 0);
+
+ _free_test_data ();
+}
+
+/**
+ * @brief Test for caps negotiation failed.
+ */
+TEST (tensor_sink_test, caps_error)
+{
+ const guint num_buffers = 10;
+ gchar *str_pipeline;
+
+ g_test_data.received = 0;
+ g_test_data.loop = g_main_loop_new (NULL, FALSE);
+
+ /** cannot link videoconvert and tensor_sink */
+ str_pipeline =
+ g_strdup_printf
+ ("videotestsrc num-buffers=%d ! video/x-raw,width=160,height=120,format=RGB,framerate=(fraction)30/1 ! "
+ "videoconvert ! tensor_sink name=test_sink", num_buffers);
+ g_test_data.pipeline = gst_parse_launch (str_pipeline, NULL);
+ g_free (str_pipeline);
+
+ g_test_data.bus = gst_element_get_bus (g_test_data.pipeline);
+ gst_bus_add_signal_watch (g_test_data.bus);
+ g_signal_connect (g_test_data.bus, "message", (GCallback) _message_cb, NULL);
+
+ g_test_data.sink =
+ gst_bin_get_by_name (GST_BIN (g_test_data.pipeline), "test_sink");
+
+ g_signal_connect (g_test_data.sink, "new-data", (GCallback) _new_data_cb,
+ NULL);
+
+ _print_log ("start pipeline for caps error test");
+ gst_element_set_state (g_test_data.pipeline, GST_STATE_PLAYING);
+ g_main_loop_run (g_test_data.loop);
+ gst_element_set_state (g_test_data.pipeline, GST_STATE_NULL);
+
+ /** check error message */
+ EXPECT_EQ (g_test_data.status, TEST_ERR_MESSAGE);
+
+ /** check received buffers */
EXPECT_EQ (g_test_data.received, 0);
_free_test_data ();