summaryrefslogtreecommitdiff
path: root/gst-decoder.c
diff options
context:
space:
mode:
authorCarlos Rafael Giani <dv@pseudoterminal.org>2017-04-26 20:56:18 +0200
committerRob Clark <robdclark@gmail.com>2017-04-29 10:23:41 -0400
commit86f0ab9f8bd0f4e203ea6e6acfc7861554cdeabd (patch)
treed35a007e17eb6a072dfec273df22716306b2a716 /gst-decoder.c
parent76d2b93f40f670ac4bcd22cc1f5a6e437f3131db (diff)
downloadkmscube-86f0ab9f8bd0f4e203ea6e6acfc7861554cdeabd.tar.gz
gst-decoder.c: add bus watch
The bus watch is useful for logging state changes, printing out info/warning/error messages and handling common GStreamer activities like latency redistribution and state change requests (that are sent by elements since they are not allowed to directly change the state). State changes and error messages can also cause a dot graph of the pipeline to be generated if the GST_DEBUG_DUMP_DOT_DIR environment variable is set. See the GST_DEBUG_BIN_TO_DOT_FILE documentation for more. Signed-off-by: Carlos Rafael Giani <dv@pseudoterminal.org>
Diffstat (limited to 'gst-decoder.c')
-rw-r--r--gst-decoder.c103
1 files changed, 103 insertions, 0 deletions
diff --git a/gst-decoder.c b/gst-decoder.c
index 05d73b7..d1cb18c 100644
--- a/gst-decoder.c
+++ b/gst-decoder.c
@@ -136,11 +136,108 @@ element_added_cb(GstBin *bin, GstElement *element, gpointer user_data)
}
}
+static gboolean
+bus_watch_cb(GstBus *bus, GstMessage *msg, gpointer user_data)
+{
+ struct decoder *dec = (struct decoder *)user_data;
+
+ (void)bus;
+
+ switch (GST_MESSAGE_TYPE(msg)) {
+ case GST_MESSAGE_STATE_CHANGED: {
+ gchar *dotfilename;
+ GstState old_gst_state, cur_gst_state, pending_gst_state;
+
+ /* Only consider state change messages coming from
+ * the toplevel element. */
+ if (GST_MESSAGE_SRC(msg) != GST_OBJECT(dec->pipeline))
+ break;
+
+ gst_message_parse_state_changed(msg, &old_gst_state, &cur_gst_state, &pending_gst_state);
+
+ printf(
+ "GStreamer state change: old: %s current: %s pending: %s\n",
+ gst_element_state_get_name(old_gst_state),
+ gst_element_state_get_name(cur_gst_state),
+ gst_element_state_get_name(pending_gst_state)
+ );
+
+ dotfilename = g_strdup_printf(
+ "statechange__old-%s__cur-%s__pending-%s",
+ gst_element_state_get_name(old_gst_state),
+ gst_element_state_get_name(cur_gst_state),
+ gst_element_state_get_name(pending_gst_state)
+ );
+ GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(dec->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, dotfilename);
+ g_free(dotfilename);
+
+ break;
+ }
+ case GST_MESSAGE_REQUEST_STATE: {
+ GstState requested_state;
+ gst_message_parse_request_state(msg, &requested_state);
+ printf(
+ "state change to %s was requested by %s\n",
+ gst_element_state_get_name(requested_state),
+ GST_MESSAGE_SRC_NAME(msg)
+ );
+ gst_element_set_state(GST_ELEMENT(dec->pipeline), requested_state);
+ break;
+ }
+ case GST_MESSAGE_LATENCY: {
+ printf("redistributing latency\n");
+ gst_bin_recalculate_latency(GST_BIN(dec->pipeline));
+ break;
+ }
+ case GST_MESSAGE_INFO:
+ case GST_MESSAGE_WARNING:
+ case GST_MESSAGE_ERROR: {
+ GError *error = NULL;
+ gchar *debug_info = NULL;
+ gchar const *prefix;
+
+ switch (GST_MESSAGE_TYPE(msg)) {
+ case GST_MESSAGE_INFO:
+ gst_message_parse_info(msg, &error, &debug_info);
+ prefix = "INFO";
+ break;
+ case GST_MESSAGE_WARNING:
+ gst_message_parse_warning(msg, &error, &debug_info);
+ prefix = "WARNING";
+ break;
+ case GST_MESSAGE_ERROR:
+ gst_message_parse_error(msg, &error, &debug_info);
+ prefix = "ERROR";
+ break;
+ default:
+ g_assert_not_reached();
+ }
+ printf("GStreamer %s: %s; debug info: %s", prefix, error->message, debug_info);
+
+ g_clear_error(&error);
+ g_free(debug_info);
+
+ if (GST_MESSAGE_TYPE(msg) == GST_MESSAGE_ERROR) {
+ GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(dec->pipeline), GST_DEBUG_GRAPH_SHOW_ALL, "error");
+ }
+
+ // TODO: stop mainloop in case of an error
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ return TRUE;
+}
+
struct decoder *
video_init(const struct egl *egl, const struct gbm *gbm, const char *filename)
{
struct decoder *dec;
GstElement *src, *decodebin;
+ GstBus *bus;
dec = calloc(1, sizeof(*dec));
dec->loop = g_main_loop_new(NULL, FALSE);
@@ -171,6 +268,12 @@ video_init(const struct egl *egl, const struct gbm *gbm, const char *filename)
decodebin = gst_bin_get_by_name(GST_BIN(dec->pipeline), "decode");
g_signal_connect(decodebin, "element-added", G_CALLBACK(element_added_cb), dec);
+ /* add bus to be able to receive error message, handle latency
+ * requests, produce pipeline dumps, etc. */
+ bus = gst_pipeline_get_bus(GST_PIPELINE(dec->pipeline));
+ gst_bus_add_watch(bus, bus_watch_cb, dec);
+ gst_object_unref(GST_OBJECT(bus));
+
/* let 'er rip! */
gst_element_set_state(dec->pipeline, GST_STATE_PLAYING);