From a059ba3520276e5fea39499028fa2d7eb00dcbc8 Mon Sep 17 00:00:00 2001 From: Carlos Gomez Date: Wed, 17 Jul 2019 16:38:29 -0600 Subject: [PATCH 1/2] Add support for step events --- gst_client/gst_client.c | 3 ++ gstd/gstd_event_factory.c | 89 ++++++++++++++++++++++++++++++++++++++- gstd/gstd_parser.c | 28 ++++++++++++ libgstc/libgstc.c | 31 ++++++++++++++ libgstc/libgstc.h | 26 ++++++++++++ 5 files changed, 176 insertions(+), 1 deletion(-) diff --git a/gst_client/gst_client.c b/gst_client/gst_client.c index acf7bb70..e122368c 100644 --- a/gst_client/gst_client.c +++ b/gst_client/gst_client.c @@ -173,6 +173,9 @@ static GstdClientCmd cmds[] = { {"event_seek", gstd_client_cmd_socket, "Perform a seek in the given pipeline", "event_seek "}, + {"event_step", gstd_client_cmd_socket, + "Perform a step event in the given pipeline", + "event_step "}, {"event_flush_start", gstd_client_cmd_socket, "Put the pipeline in flushing mode", "event_flush_start "}, diff --git a/gstd/gstd_event_factory.c b/gstd/gstd_event_factory.c index 968cdaee..6fa16b1d 100644 --- a/gstd/gstd_event_factory.c +++ b/gstd/gstd_event_factory.c @@ -35,6 +35,12 @@ #define GSTD_EVENT_FACTORY_SEEK_STOP_TYPE_DEFAULT GST_SEEK_TYPE_SET #define GSTD_EVENT_FACTORY_SEEK_STOP_DEFAULT GST_CLOCK_TIME_NONE #define GSTD_EVENT_FACTORY_FLUSH_STOP_RESET_DEFAULT TRUE +#define GSTD_EVENT_FACTORY_STEP_FORMAT_DEFAULT GST_FORMAT_BUFFERS +#define GSTD_EVENT_FACTORY_STEP_AMOUNT_DEFAULT 1 +#define GSTD_EVENT_FACTORY_STEP_RATE_DEFAULT 1.0 +#define GSTD_EVENT_FACTORY_STEP_FLUSH_DEFAULT TRUE +#define GSTD_EVENT_FACTORY_STEP_INTERMEDIATE_DEFAULT FALSE + typedef enum _GstdEventType GstdEventType; @@ -71,7 +77,9 @@ enum _GstdEventType GSTD_EVENT_SEEK = 14, - GSTD_EVENT_NAVIGATION = 15 + GSTD_EVENT_NAVIGATION = 15, + + GSTD_EVENT_STEP = 16 }; static gboolean gstd_ascii_to_gint64 (const gchar *, gint64 *); @@ -79,6 +87,7 @@ static gboolean gstd_ascii_to_double (const gchar *, gdouble *); static gboolean gstd_ascii_to_boolean (const gchar *, gboolean *); GstdEventType gstd_event_factory_parse_event (const gchar *); static GstEvent *gstd_event_factory_make_seek_event (const gchar *); +static GstEvent *gstd_event_factory_make_step_event (const gchar *); static GstEvent *gstd_event_factory_make_flush_stop_event (const gchar *); GstEvent * @@ -105,6 +114,9 @@ gstd_event_factory_make (const gchar * name, const gchar * description) case GSTD_EVENT_FLUSH_STOP: event = gstd_event_factory_make_flush_stop_event (description); break; + case GSTD_EVENT_STEP: + event = gstd_event_factory_make_step_event (description); + break; default: event = NULL; break; @@ -254,6 +266,79 @@ gstd_event_factory_make_seek_event (const gchar * description) } } +static GstEvent * +gstd_event_factory_make_step_event (const gchar * description) +{ + GstFormat format = GSTD_EVENT_FACTORY_STEP_FORMAT_DEFAULT; + guint64 amount = GSTD_EVENT_FACTORY_STEP_AMOUNT_DEFAULT; + gdouble rate = GSTD_EVENT_FACTORY_STEP_RATE_DEFAULT; + gboolean flush = GSTD_EVENT_FACTORY_STEP_FLUSH_DEFAULT; + gboolean intermediate = GSTD_EVENT_FACTORY_STEP_INTERMEDIATE_DEFAULT; + GstEvent *event = NULL; + gchar **tokens = NULL; + gint64 temp_format; + gint64 temp_flush; + gint64 temp_intermediate; + + if (NULL != description) { + tokens = g_strsplit (description, " ", 5); + } + + if (NULL == tokens || NULL == tokens[0]) { + goto fallback; + } + + if (!gstd_ascii_to_gint64 (tokens[0], &temp_format)) { + goto out; + } + format = (GstFormat) temp_format; + + if (NULL == tokens[1]) { + goto fallback; + } + + if (!gstd_ascii_to_gint64 (tokens[1], &amount)) { + goto out; + } + + if (NULL == tokens[2]) { + goto fallback; + } + + if (!gstd_ascii_to_double (tokens[2], &rate)) { + goto out; + } + + if (NULL == tokens[3]) { + goto fallback; + } + + if (!gstd_ascii_to_gint64 (tokens[3], &temp_flush)) { + goto out; + } + flush = (gboolean) temp_flush; + + if (NULL == tokens[4]) { + goto fallback; + } + + if (!gstd_ascii_to_gint64 (tokens[4], &temp_intermediate)) { + goto out; + } + intermediate = (gboolean) temp_intermediate; + +fallback: + { + event = + gst_event_new_step (format, amount, rate, flush, intermediate); + } +out: + { + g_strfreev (tokens); + return event; + } +} + static GstEvent * gstd_event_factory_make_flush_stop_event (const gchar * description) { @@ -284,6 +369,8 @@ gstd_event_factory_parse_event (const gchar * name) ret = GSTD_EVENT_FLUSH_START; } else if (!strcmp (name, "flush-stop") || !strcmp (name, "flush_stop")) { ret = GSTD_EVENT_FLUSH_STOP; + } else if (!strcmp (name, "step")) { + ret = GSTD_EVENT_STEP; } return ret; } diff --git a/gstd/gstd_parser.c b/gstd/gstd_parser.c index 5fcc2341..c4fb5a49 100644 --- a/gstd/gstd_parser.c +++ b/gstd/gstd_parser.c @@ -73,6 +73,8 @@ static GstdReturnCode gstd_parser_event_eos (GstdSession *, gchar *, gchar *, gchar **); static GstdReturnCode gstd_parser_event_seek (GstdSession *, gchar *, gchar *, gchar **); +static GstdReturnCode gstd_parser_event_step (GstdSession *, gchar *, gchar *, + gchar **); static GstdReturnCode gstd_parser_event_flush_start (GstdSession *, gchar *, gchar *, gchar **); static GstdReturnCode gstd_parser_event_flush_stop (GstdSession *, gchar *, @@ -125,6 +127,7 @@ static GstdCmd cmds[] = { {"event_eos", gstd_parser_event_eos}, {"event_seek", gstd_parser_event_seek}, + {"event_step", gstd_parser_event_step}, {"event_flush_start", gstd_parser_event_flush_start}, {"event_flush_stop", gstd_parser_event_flush_stop}, @@ -668,6 +671,31 @@ gstd_parser_event_seek (GstdSession * session, gchar * action, gchar * args, return ret; } +static GstdReturnCode +gstd_parser_event_step (GstdSession * session, gchar * action, gchar * args, + gchar ** response) +{ + GstdReturnCode ret; + gchar *uri; + gchar **tokens; + + g_return_val_if_fail (GSTD_IS_SESSION (session), GSTD_NULL_ARGUMENT); + g_return_val_if_fail (args, GSTD_NULL_ARGUMENT); + g_return_val_if_fail (response, GSTD_NULL_ARGUMENT); + + tokens = g_strsplit (args, " ", 2); + check_argument (tokens[0], GSTD_BAD_COMMAND); + // We don't check for the second token since we want to allow defaults + + uri = g_strdup_printf ("/pipelines/%s/event step %s", tokens[0], tokens[1]); + ret = gstd_parser_parse_raw_cmd (session, (gchar*)"create", uri, response); + + g_free (uri); + g_strfreev (tokens); + + return ret; +} + static GstdReturnCode gstd_parser_event_flush_start (GstdSession * session, gchar * action, gchar * pipeline, gchar ** response) diff --git a/libgstc/libgstc.c b/libgstc/libgstc.c index 585bcc1c..34f5f4d7 100644 --- a/libgstc/libgstc.c +++ b/libgstc/libgstc.c @@ -61,6 +61,7 @@ #define PIPELINE_EVENT_FORMAT "/pipelines/%s/event" #define SEEK_FORMAT "seek %f %d %d %d %lld %d %lld" +#define STEP_FORMAT "step %d %lld %f %d %d" #define FLUSH_STOP_FORMAT "flush_stop %s" #define TIMEOUT_FORMAT "%lli" @@ -670,6 +671,36 @@ gstc_pipeline_seek(GstClient *client, const char *pipeline_name, return ret; } +GstcStatus +gstc_pipeline_step(GstClient *client, const char *pipeline_name, + int format, long long amount, double rate, int flush, + int intermediate) +{ + GstcStatus ret; + int asprintf_ret; + char *where; + char *what; + + gstc_assert_and_ret_val (NULL != client, GSTC_NULL_ARGUMENT); + gstc_assert_and_ret_val (NULL != pipeline_name, GSTC_NULL_ARGUMENT); + + asprintf_ret = asprintf (&where, PIPELINE_EVENT_FORMAT, pipeline_name); + if(asprintf_ret == PRINTF_ERROR) { + return GSTC_OOM; + } + asprintf_ret = asprintf (&what, STEP_FORMAT, format, amount, rate, flush, intermediate); + if(asprintf_ret == PRINTF_ERROR) { + return GSTC_OOM; + } + + ret = gstc_cmd_create (client, where, what); + + free (where); + free (what); + + return ret; +} + GstcStatus gstc_pipeline_list_elements (GstClient * client, const char *pipeline_name, char **elements[], int *list_lenght) diff --git a/libgstc/libgstc.h b/libgstc/libgstc.h index c9e97069..6e208062 100644 --- a/libgstc/libgstc.h +++ b/libgstc/libgstc.h @@ -420,6 +420,32 @@ GstcStatus gstc_pipeline_seek(GstClient *client, const char *pname, int stop_type, long long stop); +/** + * gstc_pipeline_step: + * @client: The client returned by gstc_client_new() + * @pname: Name associated with the pipeline + * @format: Format for seek values: undefined (0), default (1), bytes (2), + * nanoseconds(3), buffers (4) or percent (5) where default means to use the + * format of the pad/element, nanoseconds means time in nanoseconds and percentage + * means percentage of the stream. + * @amount: the amount of data to step + * @rate: New playback rate, e.g. 1 is normal, 0.5 is half speed, + * 2 is twice as fast as normal. A rate of <= 0.0 is not allowed. + * @flush: The flush flag will clear any pending data in the pipeline before starting the step operation: false (0), true (1). + * @intermediate: The intermediate flag instructs the pipeline that this step operation is part of a larger step operation: false (0), true (1). + * + * Creates a new step event. The purpose of the step event is to instruct a sink to skip + * @amount (expressed in @format) of media. It can be used to implement stepping through + * the video frame by frame or for doing fast trick modes. + * + * Returns: GstcStatus indicating success, daemon unreachable, daemon timeout, + * bad pipeline name, out of memory + */ +GstcStatus gstc_pipeline_step(GstClient *client, const char *pname, + int format, long long amount, double rate, int flush, + int intermediate); + + /** * Configures playback of the pipeline between @start to @stop at the speed * given in @rate. Effectively causes gstd to invoke gst_element_seek(). From 90b2e4203f5dd36a28ac0b3be57286dc0f91276c Mon Sep 17 00:00:00 2001 From: Carlos Gomez Date: Fri, 9 Aug 2019 09:32:33 -0600 Subject: [PATCH 2/2] Use C Code Style for comments --- gstd/gstd_parser.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/gstd/gstd_parser.c b/gstd/gstd_parser.c index c4fb5a49..e996e7ad 100644 --- a/gstd/gstd_parser.c +++ b/gstd/gstd_parser.c @@ -162,7 +162,7 @@ gstd_parser_parse_raw_cmd (GstdSession * session, gchar * action, gchar * args, uri = tokens[0]; rest = tokens[1]; - // Alias the empty string to the base + /* Alias the empty string to the base */ if (!uri) uri = (gchar*)"/"; @@ -240,10 +240,10 @@ gstd_parser_create (GstdSession * session, GstdObject * obj, gchar * args, g_return_val_if_fail (GSTD_IS_SESSION (session), GSTD_NULL_ARGUMENT); g_return_val_if_fail (G_IS_OBJECT (obj), GSTD_NULL_ARGUMENT); - // This may mean a potential leak + /* This may mean a potential leak */ g_warn_if_fail (!*response); - // Tokens has the form {, } + /* Tokens has the form {, } */ if (NULL == args) { name = NULL; description = NULL; @@ -284,10 +284,10 @@ gstd_parser_read (GstdSession * session, GstdObject * obj, gchar * args, g_return_val_if_fail (GSTD_IS_SESSION (session), GSTD_NULL_ARGUMENT); g_return_val_if_fail (GSTD_IS_OBJECT (obj), GSTD_NULL_ARGUMENT); - // This may mean a potential leak + /* This may mean a potential leak */ g_warn_if_fail (!*response); - // Print the raw object + /* Print the raw object */ return gstd_object_to_string (obj, response); } @@ -660,7 +660,7 @@ gstd_parser_event_seek (GstdSession * session, gchar * action, gchar * args, tokens = g_strsplit (args, " ", 2); check_argument (tokens[0], GSTD_BAD_COMMAND); - // We don't check for the second token since we want to allow defaults + /* We don't check for the second token since we want to allow defaults */ uri = g_strdup_printf ("/pipelines/%s/event seek %s", tokens[0], tokens[1]); ret = gstd_parser_parse_raw_cmd (session, (gchar*)"create", uri, response); @@ -685,7 +685,7 @@ gstd_parser_event_step (GstdSession * session, gchar * action, gchar * args, tokens = g_strsplit (args, " ", 2); check_argument (tokens[0], GSTD_BAD_COMMAND); - // We don't check for the second token since we want to allow defaults + /* We don't check for the second token since we want to allow defaults */ uri = g_strdup_printf ("/pipelines/%s/event step %s", tokens[0], tokens[1]); ret = gstd_parser_parse_raw_cmd (session, (gchar*)"create", uri, response); @@ -729,7 +729,7 @@ gstd_parser_event_flush_stop (GstdSession * session, gchar * action, gchar * arg tokens = g_strsplit (args, " ", 2); check_argument (tokens[0], GSTD_BAD_COMMAND); - // We don't check for the second token since we want to allow defaults + /* We don't check for the second token since we want to allow defaults */ uri = g_strdup_printf ("/pipelines/%s/event flush_stop %s", tokens[0],