summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThibault Saunier <tsaunier@igalia.com>2020-11-25 22:25:28 -0300
committerGStreamer Merge Bot <gitlab-merge-bot@gstreamer-foundation.org>2021-02-26 15:37:23 +0000
commit984f0c2d2f1759508886e1ba3ddb7e55acc8059a (patch)
tree94bdb8e9cbd5a90862e4a82c5117d9f5a5edd577
parent7cf6e4d8f237d5ead7d6932ab2ea9f01887358d2 (diff)
downloadgstreamer-plugins-bad-984f0c2d2f1759508886e1ba3ddb7e55acc8059a.tar.gz
transcoder: Port to a GstBus API instead
Following the move made by GstPlayer in: https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/35 Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-bad/-/merge_requests/1840>
-rw-r--r--gst-libs/gst/transcoder/gsttranscoder-message-private.h30
-rw-r--r--gst-libs/gst/transcoder/gsttranscoder-signal-adapter.c342
-rw-r--r--gst-libs/gst/transcoder/gsttranscoder-signal-adapter.h61
-rw-r--r--gst-libs/gst/transcoder/gsttranscoder.c652
-rw-r--r--gst-libs/gst/transcoder/gsttranscoder.h102
-rw-r--r--gst-libs/gst/transcoder/meson.build4
-rw-r--r--tools/gst-transcoder.c18
7 files changed, 716 insertions, 493 deletions
diff --git a/gst-libs/gst/transcoder/gsttranscoder-message-private.h b/gst-libs/gst/transcoder/gsttranscoder-message-private.h
new file mode 100644
index 000000000..2c2ba213d
--- /dev/null
+++ b/gst-libs/gst/transcoder/gsttranscoder-message-private.h
@@ -0,0 +1,30 @@
+/* GStreamer
+ *
+ * Copyright (C) 2020 Stephan Hesse <stephan@emliri.com>
+ * Copyright (C) 2020 Thibault Saunier <tsaunier@igalia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * 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.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#define GST_TRANSCODER_MESSAGE_DATA "gst-transcoder-message-data"
+#define GST_TRANSCODER_MESSAGE_DATA_TYPE "transcoder-message-type"
+#define GST_TRANSCODER_MESSAGE_DATA_POSITION "position"
+#define GST_TRANSCODER_MESSAGE_DATA_DURATION "duration"
+#define GST_TRANSCODER_MESSAGE_DATA_ERROR "error"
+#define GST_TRANSCODER_MESSAGE_DATA_WARNING "warning"
+#define GST_TRANSCODER_MESSAGE_DATA_ISSUE_DETAILS "issue-details"
diff --git a/gst-libs/gst/transcoder/gsttranscoder-signal-adapter.c b/gst-libs/gst/transcoder/gsttranscoder-signal-adapter.c
new file mode 100644
index 000000000..ac4127598
--- /dev/null
+++ b/gst-libs/gst/transcoder/gsttranscoder-signal-adapter.c
@@ -0,0 +1,342 @@
+/* GStreamer
+ *
+ * Copyright (C) 2019-2020 Stephan Hesse <stephan@emliri.com>
+ * Copyright (C) 2020 Thibault Saunier <tsaunier@igalia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * 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.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gsttranscoder.h"
+#include "gsttranscoder-signal-adapter.h"
+
+#include "gsttranscoder-message-private.h"
+
+#include <gst/gst.h>
+
+GST_DEBUG_CATEGORY_STATIC (gst_transcoder_signal_adapter_debug);
+#define GST_CAT_DEFAULT gst_transcoder_signal_adapter_debug
+
+enum
+{
+ SIGNAL_POSITION_UPDATED,
+ SIGNAL_DURATION_CHANGED,
+ SIGNAL_DONE,
+ SIGNAL_ERROR,
+ SIGNAL_WARNING,
+ SIGNAL_LAST
+};
+
+enum
+{
+ PROP_0,
+ PROP_TRANSCODER,
+ PROP_LAST
+};
+
+static GParamSpec *param_specs[PROP_LAST] = { NULL, };
+
+struct _GstTranscoderSignalAdapter
+{
+ GObject parent;
+ GstBus *bus;
+ GSource *source;
+
+ GstTranscoder *transcoder;
+};
+
+struct _GstTranscoderSignalAdapterClass
+{
+ GObjectClass parent_class;
+};
+
+#define _do_init \
+ GST_DEBUG_CATEGORY_INIT (gst_transcoder_signal_adapter_debug, "gst-transcoder-signaladapter", \
+ 0, "GstTranscoder signal adapter")
+
+#define parent_class gst_transcoder_signal_adapter_parent_class
+G_DEFINE_TYPE_WITH_CODE (GstTranscoderSignalAdapter,
+ gst_transcoder_signal_adapter, G_TYPE_OBJECT, _do_init);
+
+static guint signals[SIGNAL_LAST] = { 0, };
+
+static void
+gst_transcoder_signal_adapter_emit (GstTranscoderSignalAdapter * self,
+ const GstStructure * message_data)
+{
+ GstTranscoderMessage transcoder_message_type;
+ g_return_if_fail (g_str_equal (gst_structure_get_name (message_data),
+ GST_TRANSCODER_MESSAGE_DATA));
+
+ GST_LOG ("Emitting message %" GST_PTR_FORMAT, message_data);
+ gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_TYPE,
+ GST_TYPE_TRANSCODER_MESSAGE, &transcoder_message_type, NULL);
+
+ switch (transcoder_message_type) {
+ case GST_TRANSCODER_MESSAGE_POSITION_UPDATED:{
+ GstClockTime pos = GST_CLOCK_TIME_NONE;
+ gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_POSITION,
+ GST_TYPE_CLOCK_TIME, &pos, NULL);
+ g_signal_emit (self, signals[SIGNAL_POSITION_UPDATED], 0, pos);
+ break;
+ }
+ case GST_TRANSCODER_MESSAGE_DURATION_CHANGED:{
+ GstClockTime duration = GST_CLOCK_TIME_NONE;
+ gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_DURATION,
+ GST_TYPE_CLOCK_TIME, &duration, NULL);
+ g_signal_emit (self, signals[SIGNAL_DURATION_CHANGED], 0, duration);
+ break;
+ }
+ case GST_TRANSCODER_MESSAGE_DONE:
+ g_signal_emit (self, signals[SIGNAL_DONE], 0);
+ break;
+ case GST_TRANSCODER_MESSAGE_ERROR:{
+ GError *error = NULL;
+ GstStructure *details;
+
+ gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_ERROR,
+ G_TYPE_ERROR, &error, GST_TYPE_STRUCTURE, &details, NULL);
+ g_signal_emit (self, signals[SIGNAL_ERROR], 0, error, details);
+ g_error_free (error);
+ if (details)
+ gst_structure_free (details);
+ break;
+ }
+ case GST_TRANSCODER_MESSAGE_WARNING:{
+ GstStructure *details;
+ GError *error = NULL;
+
+ gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_WARNING,
+ G_TYPE_ERROR, &error, GST_TYPE_STRUCTURE, &details, NULL);
+ g_signal_emit (self, signals[SIGNAL_WARNING], 0, error, details);
+ g_error_free (error);
+ if (details)
+ gst_structure_free (details);
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+/*
+ * callback for the bus-message in-sync handling
+ */
+static GstBusSyncReply
+ gst_transcoder_signal_adapter_bus_sync_handler
+ (GstBus * bus, GstMessage * message, gpointer user_data)
+{
+ GstTranscoderSignalAdapter *self = GST_TRANSCODER_SIGNAL_ADAPTER (user_data);
+ const GstStructure *message_data = gst_message_get_structure (message);
+ gst_transcoder_signal_adapter_emit (self, message_data);
+ gst_message_unref (message);
+ return GST_BUS_DROP;
+}
+
+/*
+ * callback for the bus-watch
+ * pre: there is a message on the bus
+ */
+static gboolean
+gst_transcoder_signal_adapter_on_message (GstBus * bus,
+ GstMessage * message, gpointer user_data)
+{
+ GstTranscoderSignalAdapter *self = GST_TRANSCODER_SIGNAL_ADAPTER (user_data);
+ const GstStructure *message_data = gst_message_get_structure (message);
+ gst_transcoder_signal_adapter_emit (self, message_data);
+ return TRUE;
+}
+
+/**
+ * gst_transcoder_signal_adapter_new:
+ * @transcoder: (transfer none): #GstTranscoder instance to emit signals for.
+ * @context: (nullable): A #GMainContext on which the main-loop will process
+ * transcoder bus messages on. Can be NULL (thread-default
+ * context will be used then).
+ *
+ * A bus-watching #GSource will be created and attached to the context. The
+ * attached callback will emit the corresponding signal for the message
+ * received. Matching signals for transcoder messages from the bus will be
+ * emitted by it on the created adapter object.
+ *
+ * Returns: (transfer full)(nullable): A new #GstTranscoderSignalAdapter to
+ * connect signal handlers to.
+ *
+ * Since: 1.20
+ */
+GstTranscoderSignalAdapter *
+gst_transcoder_signal_adapter_new (GstTranscoder * transcoder,
+ GMainContext * context)
+{
+ GstTranscoderSignalAdapter *self = NULL;
+
+ g_return_val_if_fail (GST_IS_TRANSCODER (transcoder), NULL);
+
+ if (!context) {
+ context = g_main_context_get_thread_default ();
+ }
+
+ self = g_object_new (GST_TYPE_TRANSCODER_SIGNAL_ADAPTER, NULL);
+ self->bus = gst_transcoder_get_message_bus (transcoder);
+ self->source = gst_bus_create_watch (self->bus);
+
+ if (!self->source) {
+ GST_ERROR_OBJECT (transcoder, "Could not create watch.");
+
+ gst_object_unref (self);
+
+ return NULL;
+ }
+
+ g_source_attach (self->source, context);
+ g_source_set_callback (self->source,
+ (GSourceFunc) gst_transcoder_signal_adapter_on_message, self, NULL);
+ return self;
+}
+
+/**
+ * gst_transcoder_signal_adapter_new_sync_emit:
+ * @transcoder: (transfer none): #GstTranscoder instance to emit signals
+ * synchronously for.
+ *
+ * Returns: (transfer full): A new #GstTranscoderSignalAdapter to connect signal
+ * handlers to.
+ *
+ * Since: 1.20
+ */
+GstTranscoderSignalAdapter *
+gst_transcoder_signal_adapter_new_sync_emit (GstTranscoder * transcoder)
+{
+ GstBus *bus = NULL;
+ GstTranscoderSignalAdapter *self = NULL;
+
+ g_return_val_if_fail (GST_IS_TRANSCODER (transcoder), NULL);
+
+ bus = gst_transcoder_get_message_bus (transcoder);
+
+ self = g_object_new (GST_TYPE_TRANSCODER_SIGNAL_ADAPTER, NULL);
+ self->bus = bus;
+ gst_bus_set_sync_handler (self->bus,
+ gst_transcoder_signal_adapter_bus_sync_handler, self, NULL);
+ return self;
+}
+
+static void
+gst_transcoder_signal_adapter_init (GstTranscoderSignalAdapter * self)
+{
+ self->source = NULL;
+}
+
+static void
+gst_transcoder_signal_adapter_dispose (GObject * object)
+{
+ GstTranscoderSignalAdapter *self = GST_TRANSCODER_SIGNAL_ADAPTER (object);
+
+ if (self->source) {
+ g_source_destroy (self->source);
+ g_source_unref (self->source);
+ self->source = NULL;
+ }
+
+ gst_clear_object (&self->bus);
+ gst_clear_object (&self->transcoder);
+
+ G_OBJECT_CLASS (parent_class)->dispose (object);
+}
+
+static void
+gst_transcoder_signal_adapter_get_property (GObject * object, guint prop_id,
+ GValue * value, GParamSpec * pspec)
+{
+ GstTranscoderSignalAdapter *self = GST_TRANSCODER_SIGNAL_ADAPTER (object);
+
+ switch (prop_id) {
+ case PROP_TRANSCODER:
+ g_value_set_object (value, self->transcoder);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gst_transcoder_signal_adapter_class_init (GstTranscoderSignalAdapterClass *
+ klass)
+{
+ GObjectClass *gobject_class = (GObjectClass *) klass;
+
+ gobject_class->dispose = gst_transcoder_signal_adapter_dispose;
+ gobject_class->get_property = gst_transcoder_signal_adapter_get_property;
+
+ signals[SIGNAL_POSITION_UPDATED] =
+ g_signal_new ("position-updated", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
+ NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
+
+ signals[SIGNAL_DURATION_CHANGED] =
+ g_signal_new ("duration-changed", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
+ NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
+
+ signals[SIGNAL_DONE] =
+ g_signal_new ("done", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
+ NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
+
+ signals[SIGNAL_ERROR] =
+ g_signal_new ("error", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
+ NULL, NULL, G_TYPE_NONE, 2, G_TYPE_ERROR, GST_TYPE_STRUCTURE);
+
+ signals[SIGNAL_WARNING] =
+ g_signal_new ("warning", G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
+ NULL, NULL, G_TYPE_NONE, 2, G_TYPE_ERROR, GST_TYPE_STRUCTURE);
+
+ /**
+ * GstTranscoderSignalAdapter:transcoder:
+ *
+ * The #GstTranscoder tracked by the adapter.
+ *
+ * Since: 1.20
+ */
+ param_specs[PROP_TRANSCODER] =
+ g_param_spec_object ("transcoder", "Transcoder",
+ "The GstTranscoder @self is tracking", GST_TYPE_TRANSCODER,
+ G_PARAM_READABLE);
+
+ g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
+}
+
+
+/**
+ * gst_transcoder_signal_adapter_get_transcoder:
+ * @self: The #GstTranscoderSignalAdapter
+ *
+ * Returns: (transfer full): The #GstTranscoder @self is tracking
+ *
+ * Since: 1.20
+ */
+GstTranscoder *
+gst_transcoder_signal_adapter_get_transcoder (GstTranscoderSignalAdapter * self)
+{
+ return gst_object_ref (self->transcoder);
+}
diff --git a/gst-libs/gst/transcoder/gsttranscoder-signal-adapter.h b/gst-libs/gst/transcoder/gsttranscoder-signal-adapter.h
new file mode 100644
index 000000000..6dda12437
--- /dev/null
+++ b/gst-libs/gst/transcoder/gsttranscoder-signal-adapter.h
@@ -0,0 +1,61 @@
+/* GStreamer
+ *
+ * Copyright (C) 2019-2020 Stephan Hesse <stephan@emliri.com>
+ * Copyright (C) 2020 Thibault Saunier <tsaunier@igalia.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * 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.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+#pragma once
+
+#include <gst/gst.h>
+#include <gst/transcoder/gsttranscoder.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstTranscoderSignalAdapter:
+ *
+ * Transforms #GstTranscoder bus messages to signals from the adapter object.
+ *
+ * Since: 1.20
+ */
+
+/**
+ * GST_TYPE_TRANSCODER_SIGNAL_ADAPTER:
+ *
+ * Since: 1.20
+ */
+#define GST_TYPE_TRANSCODER_SIGNAL_ADAPTER (gst_transcoder_signal_adapter_get_type ())
+GST_TRANSCODER_API
+
+/**
+ * GstTranscoderSignalAdapterClass:
+ *
+ * Since: 1.20
+ */
+G_DECLARE_FINAL_TYPE(GstTranscoderSignalAdapter, gst_transcoder_signal_adapter, GST, TRANSCODER_SIGNAL_ADAPTER, GObject)
+
+GST_TRANSCODER_API
+GstTranscoderSignalAdapter * gst_transcoder_signal_adapter_new_sync_emit (GstTranscoder * transcoder);
+
+GST_TRANSCODER_API
+GstTranscoderSignalAdapter * gst_transcoder_signal_adapter_new (GstTranscoder * transcoder, GMainContext * context);
+
+GST_TRANSCODER_API
+GstTranscoder * gst_transcoder_signal_adapter_get_transcoder (GstTranscoderSignalAdapter * self);
+
+
+G_END_DECLS
diff --git a/gst-libs/gst/transcoder/gsttranscoder.c b/gst-libs/gst/transcoder/gsttranscoder.c
index ec7041237..2e7102274 100644
--- a/gst-libs/gst/transcoder/gsttranscoder.c
+++ b/gst-libs/gst/transcoder/gsttranscoder.c
@@ -28,6 +28,7 @@
*/
#include "gsttranscoder.h"
+#include "gsttranscoder-message-private.h"
GST_DEBUG_CATEGORY_STATIC (gst_transcoder_debug);
#define GST_CAT_DEFAULT gst_transcoder_debug
@@ -52,7 +53,6 @@ gst_transcoder_error_quark (void)
enum
{
PROP_0,
- PROP_SIGNAL_DISPATCHER,
PROP_SRC_URI,
PROP_DEST_URI,
PROP_PROFILE,
@@ -64,22 +64,10 @@ enum
PROP_LAST
};
-enum
-{
- SIGNAL_POSITION_UPDATED,
- SIGNAL_DURATION_CHANGED,
- SIGNAL_DONE,
- SIGNAL_ERROR,
- SIGNAL_WARNING,
- SIGNAL_LAST
-};
-
struct _GstTranscoder
{
GstObject parent;
- GstTranscoderSignalDispatcher *signal_dispatcher;
-
GstEncodingProfile *profile;
gchar *source_uri;
gchar *dest_uri;
@@ -99,6 +87,8 @@ struct _GstTranscoder
gint wanted_cpu_usage;
GstClockTime last_duration;
+
+ GstBus *api_bus;
};
struct _GstTranscoderClass
@@ -106,15 +96,9 @@ struct _GstTranscoderClass
GstObjectClass parent_class;
};
-static void
-gst_transcoder_signal_dispatcher_dispatch (GstTranscoderSignalDispatcher * self,
- GstTranscoder * transcoder, void (*emitter) (gpointer data), gpointer data,
- GDestroyNotify destroy);
-
#define parent_class gst_transcoder_parent_class
G_DEFINE_TYPE (GstTranscoder, gst_transcoder, GST_TYPE_OBJECT);
-static guint signals[SIGNAL_LAST] = { 0, };
static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static void gst_transcoder_dispose (GObject * object);
@@ -162,6 +146,7 @@ gst_transcoder_init (GstTranscoder * self)
self->context = g_main_context_new ();
self->loop = g_main_loop_new (self->context, FALSE);
+ self->api_bus = gst_bus_new ();
self->wanted_cpu_usage = 100;
self->position_update_interval_ms = DEFAULT_POSITION_UPDATE_INTERVAL_MS;
@@ -180,12 +165,6 @@ gst_transcoder_class_init (GstTranscoderClass * klass)
gobject_class->finalize = gst_transcoder_finalize;
gobject_class->constructed = gst_transcoder_constructed;
- param_specs[PROP_SIGNAL_DISPATCHER] =
- g_param_spec_object ("signal-dispatcher",
- "Signal Dispatcher", "Dispatcher for the signals to e.g. event loops",
- GST_TYPE_TRANSCODER_SIGNAL_DISPATCHER,
- G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
param_specs[PROP_SRC_URI] =
g_param_spec_string ("src-uri", "URI", "Source URI", DEFAULT_URI,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
@@ -232,31 +211,6 @@ gst_transcoder_class_init (GstTranscoderClass * klass)
DEFAULT_AVOID_REENCODING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
-
- signals[SIGNAL_POSITION_UPDATED] =
- g_signal_new ("position-updated", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
- NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
-
- signals[SIGNAL_DURATION_CHANGED] =
- g_signal_new ("duration-changed", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
- NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
-
- signals[SIGNAL_DONE] =
- g_signal_new ("done", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
- NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
-
- signals[SIGNAL_ERROR] =
- g_signal_new ("error", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
- NULL, NULL, G_TYPE_NONE, 2, G_TYPE_ERROR, GST_TYPE_STRUCTURE);
-
- signals[SIGNAL_WARNING] =
- g_signal_new ("warning", G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
- NULL, NULL, G_TYPE_NONE, 2, G_TYPE_ERROR, GST_TYPE_STRUCTURE);
}
static void
@@ -292,8 +246,6 @@ gst_transcoder_finalize (GObject * object)
g_free (self->source_uri);
g_free (self->dest_uri);
- if (self->signal_dispatcher)
- g_object_unref (self->signal_dispatcher);
g_cond_clear (&self->cond);
G_OBJECT_CLASS (parent_class)->finalize (object);
@@ -329,9 +281,6 @@ gst_transcoder_set_property (GObject * object, guint prop_id,
GstTranscoder *self = GST_TRANSCODER (object);
switch (prop_id) {
- case PROP_SIGNAL_DISPATCHER:
- self->signal_dispatcher = g_value_dup_object (value);
- break;
case PROP_SRC_URI:{
GST_OBJECT_LOCK (self);
g_free (self->source_uri);
@@ -441,6 +390,34 @@ gst_transcoder_get_property (GObject * object, guint prop_id,
}
}
+/*
+ * Works same as gst_structure_set to set field/type/value triplets on message data
+ */
+static void
+api_bus_post_message (GstTranscoder * self, GstTranscoderMessage message_type,
+ const gchar * firstfield, ...)
+{
+ GstStructure *message_data = NULL;
+ GstMessage *msg = NULL;
+ va_list varargs;
+
+ GST_INFO ("Posting API-bus message-type: %s",
+ gst_transcoder_message_get_name (message_type));
+ message_data = gst_structure_new (GST_TRANSCODER_MESSAGE_DATA,
+ GST_TRANSCODER_MESSAGE_DATA_TYPE, GST_TYPE_TRANSCODER_MESSAGE,
+ message_type, NULL);
+
+ va_start (varargs, firstfield);
+ gst_structure_set_valist (message_data, firstfield, varargs);
+ va_end (varargs);
+
+ msg = gst_message_new_custom (GST_MESSAGE_APPLICATION,
+ GST_OBJECT (self), message_data);
+ GST_DEBUG ("Created message with payload: [ %" GST_PTR_FORMAT " ]",
+ message_data);
+ gst_bus_post (self->api_bus, msg);
+}
+
static gboolean
main_loop_running_cb (gpointer user_data)
{
@@ -455,32 +432,6 @@ main_loop_running_cb (gpointer user_data)
return G_SOURCE_REMOVE;
}
-typedef struct
-{
- GstTranscoder *transcoder;
- GstClockTime position;
-} PositionUpdatedSignalData;
-
-static void
-position_updated_dispatch (gpointer user_data)
-{
- PositionUpdatedSignalData *data = user_data;
-
- if (data->transcoder->target_state >= GST_STATE_PAUSED) {
- g_signal_emit (data->transcoder, signals[SIGNAL_POSITION_UPDATED], 0,
- data->position);
- g_object_notify_by_pspec (G_OBJECT (data->transcoder),
- param_specs[PROP_POSITION]);
- }
-}
-
-static void
-position_updated_signal_data_free (PositionUpdatedSignalData * data)
-{
- g_object_unref (data->transcoder);
- g_free (data);
-}
-
static gboolean
tick_cb (gpointer user_data)
{
@@ -498,16 +449,9 @@ tick_cb (gpointer user_data)
GST_LOG_OBJECT (self, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
- if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
- signals[SIGNAL_POSITION_UPDATED], 0, NULL, NULL, NULL) != 0) {
- PositionUpdatedSignalData *data = g_new0 (PositionUpdatedSignalData, 1);
-
- data->transcoder = g_object_ref (self);
- data->position = position;
- gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
- position_updated_dispatch, data,
- (GDestroyNotify) position_updated_signal_data_free);
- }
+ api_bus_post_message (self, GST_TRANSCODER_MESSAGE_POSITION_UPDATED,
+ GST_TRANSCODER_MESSAGE_DATA_POSITION, GST_TYPE_CLOCK_TIME, position,
+ NULL);
return G_SOURCE_CONTINUE;
}
@@ -537,58 +481,6 @@ remove_tick_source (GstTranscoder * self)
self->tick_source = NULL;
}
-typedef struct
-{
- GstTranscoder *transcoder;
- GError *err;
- GstStructure *details;
-} IssueSignalData;
-
-static void
-error_dispatch (gpointer user_data)
-{
- IssueSignalData *data = user_data;
-
- g_signal_emit (data->transcoder, signals[SIGNAL_ERROR], 0, data->err,
- data->details);
-}
-
-static void
-free_issue_signal_data (IssueSignalData * data)
-{
- g_object_unref (data->transcoder);
- if (data->details)
- gst_structure_free (data->details);
- g_clear_error (&data->err);
- g_free (data);
-}
-
-static void
-emit_error (GstTranscoder * self, GError * err, const GstStructure * details)
-{
- if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
- signals[SIGNAL_ERROR], 0, NULL, NULL, NULL) != 0) {
- IssueSignalData *data = g_new0 (IssueSignalData, 1);
-
- data->transcoder = g_object_ref (self);
- data->err = g_error_copy (err);
- if (details)
- data->details = gst_structure_copy (details);
- gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
- error_dispatch, data, (GDestroyNotify) free_issue_signal_data);
- }
-
- g_error_free (err);
-
- remove_tick_source (self);
-
- self->target_state = GST_STATE_NULL;
- self->current_state = GST_STATE_NULL;
- self->is_live = FALSE;
- self->is_eos = FALSE;
- gst_element_set_state (self->transcodebin, GST_STATE_NULL);
-}
-
static void
dump_dot_file (GstTranscoder * self, const gchar * name)
{
@@ -603,33 +495,6 @@ dump_dot_file (GstTranscoder * self, const gchar * name)
}
static void
-warning_dispatch (gpointer user_data)
-{
- IssueSignalData *data = user_data;
-
- g_signal_emit (data->transcoder, signals[SIGNAL_WARNING], 0, data->err,
- data->details);
-}
-
-static void
-emit_warning (GstTranscoder * self, GError * err, const GstStructure * details)
-{
- if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
- signals[SIGNAL_WARNING], 0, NULL, NULL, NULL) != 0) {
- IssueSignalData *data = g_new0 (IssueSignalData, 1);
-
- data->transcoder = g_object_ref (self);
- data->err = g_error_copy (err);
- if (details)
- data->details = gst_structure_copy (details);
- gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
- warning_dispatch, data, (GDestroyNotify) free_issue_signal_data);
- }
-
- g_error_free (err);
-}
-
-static void
error_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
{
GError *err;
@@ -654,7 +519,11 @@ error_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
"msg-source-element-name", G_TYPE_STRING, "name",
"msg-source-type", G_TYPE_GTYPE, G_OBJECT_TYPE (msg->src),
"msg-error", G_TYPE_STRING, message, NULL);
- emit_error (self, g_error_copy (err), details);
+
+ api_bus_post_message (self, GST_TRANSCODER_MESSAGE_ERROR,
+ GST_TRANSCODER_MESSAGE_DATA_ERROR, G_TYPE_ERROR, err,
+ GST_TRANSCODER_MESSAGE_DATA_ISSUE_DETAILS, GST_TYPE_STRUCTURE, details,
+ NULL);
gst_structure_free (details);
g_clear_error (&err);
@@ -695,8 +564,13 @@ warning_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
transcoder_err =
g_error_new_literal (GST_TRANSCODER_ERROR, GST_TRANSCODER_ERROR_FAILED,
full_message);
- emit_warning (self, transcoder_err, details);
+ api_bus_post_message (self, GST_TRANSCODER_MESSAGE_WARNING,
+ GST_TRANSCODER_MESSAGE_DATA_WARNING, G_TYPE_ERROR, transcoder_err,
+ GST_TRANSCODER_MESSAGE_DATA_ISSUE_DETAILS, GST_TYPE_STRUCTURE, details,
+ NULL);
+
+ g_clear_error (&transcoder_err);
g_clear_error (&err);
g_free (debug);
g_free (name);
@@ -705,12 +579,6 @@ warning_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
}
static void
-eos_dispatch (gpointer user_data)
-{
- g_signal_emit (user_data, signals[SIGNAL_DONE], 0);
-}
-
-static void
eos_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
gpointer user_data)
{
@@ -723,11 +591,7 @@ eos_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
tick_cb (self);
remove_tick_source (self);
- if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
- signals[SIGNAL_DONE], 0, NULL, NULL, NULL) != 0) {
- gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
- eos_dispatch, g_object_ref (self), (GDestroyNotify) g_object_unref);
- }
+ api_bus_post_message (self, GST_TRANSCODER_MESSAGE_DONE, NULL, NULL);
self->is_eos = TRUE;
}
@@ -744,54 +608,13 @@ clock_lost_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
if (state_ret != GST_STATE_CHANGE_FAILURE)
state_ret = gst_element_set_state (self->transcodebin, GST_STATE_PLAYING);
- if (state_ret == GST_STATE_CHANGE_FAILURE)
- emit_error (self, g_error_new (GST_TRANSCODER_ERROR,
- GST_TRANSCODER_ERROR_FAILED, "Failed to handle clock loss"),
- NULL);
- }
-}
-
-typedef struct
-{
- GstTranscoder *transcoder;
- GstClockTime duration;
-} DurationChangedSignalData;
-
-static void
-duration_changed_dispatch (gpointer user_data)
-{
- DurationChangedSignalData *data = user_data;
-
- if (data->transcoder->target_state >= GST_STATE_PAUSED) {
- g_signal_emit (data->transcoder, signals[SIGNAL_DURATION_CHANGED], 0,
- data->duration);
- g_object_notify_by_pspec (G_OBJECT (data->transcoder),
- param_specs[PROP_DURATION]);
- }
-}
-
-static void
-duration_changed_signal_data_free (DurationChangedSignalData * data)
-{
- g_object_unref (data->transcoder);
- g_free (data);
-}
-
-static void
-emit_duration_changed (GstTranscoder * self, GstClockTime duration)
-{
- GST_DEBUG_OBJECT (self, "Duration changed %" GST_TIME_FORMAT,
- GST_TIME_ARGS (duration));
-
- if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
- signals[SIGNAL_DURATION_CHANGED], 0, NULL, NULL, NULL) != 0) {
- DurationChangedSignalData *data = g_new0 (DurationChangedSignalData, 1);
-
- data->transcoder = g_object_ref (self);
- data->duration = duration;
- gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
- duration_changed_dispatch, data,
- (GDestroyNotify) duration_changed_signal_data_free);
+ if (state_ret == GST_STATE_CHANGE_FAILURE) {
+ GError *err = g_error_new (GST_TRANSCODER_ERROR,
+ GST_TRANSCODER_ERROR_FAILED, "Failed to handle clock loss");
+ api_bus_post_message (self, GST_TRANSCODER_MESSAGE_ERROR,
+ GST_TRANSCODER_MESSAGE_DATA_ERROR, G_TYPE_ERROR, err, NULL);
+ g_error_free (err);
+ }
}
}
@@ -836,7 +659,9 @@ duration_changed_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
if (gst_element_query_duration (self->transcodebin, GST_FORMAT_TIME,
&duration)) {
- emit_duration_changed (self, duration);
+ api_bus_post_message (self, GST_TRANSCODER_MESSAGE_DURATION_CHANGED,
+ GST_TRANSCODER_MESSAGE_DATA_DURATION, GST_TYPE_CLOCK_TIME,
+ duration, NULL);
}
}
@@ -866,11 +691,16 @@ request_state_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg,
self->target_state = state;
state_ret = gst_element_set_state (self->transcodebin, state);
- if (state_ret == GST_STATE_CHANGE_FAILURE)
- emit_error (self, g_error_new (GST_TRANSCODER_ERROR,
- GST_TRANSCODER_ERROR_FAILED,
- "Failed to change to requested state %s",
- gst_element_state_get_name (state)), NULL);
+ if (state_ret == GST_STATE_CHANGE_FAILURE) {
+ GError *err = g_error_new (GST_TRANSCODER_ERROR,
+ GST_TRANSCODER_ERROR_FAILED,
+ "Failed to change to requested state %s",
+ gst_element_state_get_name (state));
+
+ api_bus_post_message (self, GST_TRANSCODER_MESSAGE_ERROR,
+ GST_TRANSCODER_MESSAGE_DATA_ERROR, G_TYPE_ERROR, err, NULL);
+ g_error_free (err);
+ }
}
static void
@@ -1030,7 +860,7 @@ gst_transcoder_new (const gchar * source_uri,
profile = create_encoding_profile (encoding_profile);
- return gst_transcoder_new_full (source_uri, dest_uri, profile, NULL);
+ return gst_transcoder_new_full (source_uri, dest_uri, profile);
}
/**
@@ -1040,15 +870,12 @@ gst_transcoder_new (const gchar * source_uri,
* @profile: The #GstEncodingProfile defining the output format
* have a look at the #GstEncodingProfile documentation to find more
* about the serialization format.
- * @signal_dispatcher: The #GstTranscoderSignalDispatcher to be used
- * to dispatch the various signals.
*
* Returns: a new #GstTranscoder instance
*/
GstTranscoder *
gst_transcoder_new_full (const gchar * source_uri,
- const gchar * dest_uri, GstEncodingProfile * profile,
- GstTranscoderSignalDispatcher * signal_dispatcher)
+ const gchar * dest_uri, GstEncodingProfile * profile)
{
static GOnce once = G_ONCE_INIT;
@@ -1058,8 +885,7 @@ gst_transcoder_new_full (const gchar * source_uri,
g_return_val_if_fail (dest_uri, NULL);
return g_object_new (GST_TYPE_TRANSCODER, "src-uri", source_uri,
- "dest-uri", dest_uri, "profile", profile,
- "signal-dispatcher", signal_dispatcher, NULL);
+ "dest-uri", dest_uri, "profile", profile, NULL);
}
typedef struct
@@ -1069,8 +895,7 @@ typedef struct
} RunSyncData;
static void
-_error_cb (GstTranscoder * self, GError * error, GstStructure * details,
- RunSyncData * data)
+_error_cb (RunSyncData * data, GError * error, GstStructure * details)
{
if (data->error == NULL)
g_propagate_error (&data->error, error);
@@ -1082,7 +907,7 @@ _error_cb (GstTranscoder * self, GError * error, GstStructure * details,
}
static void
-_done_cb (GstTranscoder * self, RunSyncData * data)
+_done_cb (RunSyncData * data)
{
if (data->loop) {
g_main_loop_quit (data->loop);
@@ -1103,17 +928,20 @@ gboolean
gst_transcoder_run (GstTranscoder * self, GError ** error)
{
RunSyncData data = { 0, };
+ GstTranscoderSignalAdapter *signal_adapter =
+ gst_transcoder_signal_adapter_new (self, NULL);
data.loop = g_main_loop_new (NULL, FALSE);
- g_signal_connect (self, "error", G_CALLBACK (_error_cb), &data);
- g_signal_connect (self, "done", G_CALLBACK (_done_cb), &data);
+ g_signal_connect_swapped (signal_adapter, "error", G_CALLBACK (_error_cb),
+ &data);
+ g_signal_connect_swapped (signal_adapter, "done", G_CALLBACK (_done_cb),
+ &data);
gst_transcoder_run_async (self);
if (!data.error)
g_main_loop_run (data.loop);
- g_signal_handlers_disconnect_by_func (self, _error_cb, &data);
- g_signal_handlers_disconnect_by_func (self, _done_cb, &data);
+ g_object_unref (signal_adapter);
if (data.error) {
if (error)
@@ -1143,8 +971,12 @@ gst_transcoder_run_async (GstTranscoder * self)
GST_DEBUG_OBJECT (self, "Play");
if (!self->profile) {
- emit_error (self, g_error_new (GST_TRANSCODER_ERROR,
- GST_TRANSCODER_ERROR_FAILED, "No \"profile\" provided"), NULL);
+ GError *err = g_error_new (GST_TRANSCODER_ERROR,
+ GST_TRANSCODER_ERROR_FAILED, "No \"profile\" provided");
+
+ api_bus_post_message (self, GST_TRANSCODER_MESSAGE_ERROR,
+ GST_TRANSCODER_MESSAGE_DATA_ERROR, G_TYPE_ERROR, err, NULL);
+ g_error_free (err);
return;
}
@@ -1153,8 +985,12 @@ gst_transcoder_run_async (GstTranscoder * self)
state_ret = gst_element_set_state (self->transcodebin, GST_STATE_PLAYING);
if (state_ret == GST_STATE_CHANGE_FAILURE) {
- emit_error (self, g_error_new (GST_TRANSCODER_ERROR,
- GST_TRANSCODER_ERROR_FAILED, "Could not start transcoding"), NULL);
+ GError *err = g_error_new (GST_TRANSCODER_ERROR,
+ GST_TRANSCODER_ERROR_FAILED, "Could not start transcoding");
+ api_bus_post_message (self, GST_TRANSCODER_MESSAGE_ERROR,
+ GST_TRANSCODER_MESSAGE_DATA_ERROR, G_TYPE_ERROR, err, NULL);
+ g_error_free (err);
+
return;
} else if (state_ret == GST_STATE_CHANGE_NO_PREROLL) {
self->is_live = TRUE;
@@ -1372,212 +1208,154 @@ gst_transcoder_error_get_name (GstTranscoderError error)
return NULL;
}
-G_DEFINE_INTERFACE (GstTranscoderSignalDispatcher,
- gst_transcoder_signal_dispatcher, G_TYPE_OBJECT);
-
-static void
-gst_transcoder_signal_dispatcher_default_init (G_GNUC_UNUSED
- GstTranscoderSignalDispatcherInterface * iface)
-{
-
-}
-
-static void
-gst_transcoder_signal_dispatcher_dispatch (GstTranscoderSignalDispatcher * self,
- GstTranscoder * transcoder, void (*emitter) (gpointer data), gpointer data,
- GDestroyNotify destroy)
-{
- GstTranscoderSignalDispatcherInterface *iface;
-
- if (!self) {
- emitter (data);
- if (destroy)
- destroy (data);
- return;
- }
-
- g_return_if_fail (GST_IS_TRANSCODER_SIGNAL_DISPATCHER (self));
- iface = GST_TRANSCODER_SIGNAL_DISPATCHER_GET_INTERFACE (self);
- g_return_if_fail (iface->dispatch != NULL);
-
- iface->dispatch (self, transcoder, emitter, data, destroy);
-}
-
-struct _GstTranscoderGMainContextSignalDispatcher
-{
- GObject parent;
- GMainContext *application_context;
-};
-
-struct _GstTranscoderGMainContextSignalDispatcherClass
-{
- GObjectClass parent_class;
-};
-
-static void
- gst_transcoder_g_main_context_signal_dispatcher_interface_init
- (GstTranscoderSignalDispatcherInterface * iface);
-
-enum
-{
- G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_0,
- G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT,
- G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST
-};
-
-G_DEFINE_TYPE_WITH_CODE (GstTranscoderGMainContextSignalDispatcher,
- gst_transcoder_g_main_context_signal_dispatcher, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (GST_TYPE_TRANSCODER_SIGNAL_DISPATCHER,
- gst_transcoder_g_main_context_signal_dispatcher_interface_init));
-
-static GParamSpec
- * g_main_context_signal_dispatcher_param_specs
- [G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST] = { NULL, };
-
-static void
-gst_transcoder_g_main_context_signal_dispatcher_finalize (GObject * object)
-{
- GstTranscoderGMainContextSignalDispatcher *self =
- GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
-
- if (self->application_context)
- g_main_context_unref (self->application_context);
-
- G_OBJECT_CLASS
- (gst_transcoder_g_main_context_signal_dispatcher_parent_class)->finalize
- (object);
-}
-
-static void
-gst_transcoder_g_main_context_signal_dispatcher_set_property (GObject * object,
- guint prop_id, const GValue * value, GParamSpec * pspec)
-{
- GstTranscoderGMainContextSignalDispatcher *self =
- GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
-
- switch (prop_id) {
- case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
- self->application_context = g_value_dup_boxed (value);
- if (!self->application_context)
- self->application_context = g_main_context_ref_thread_default ();
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
-}
-
-static void
-gst_transcoder_g_main_context_signal_dispatcher_get_property (GObject * object,
- guint prop_id, GValue * value, GParamSpec * pspec)
+/**
+ * gst_transcoder_get_message_bus:
+ * @transcoder: #GstTranscoder instance
+ *
+ * GstTranscoder API exposes a #GstBus instance which purpose is to provide data
+ * structures representing transcoder-internal events in form of #GstMessage-s of
+ * type GST_MESSAGE_APPLICATION.
+ *
+ * Each message carries a "transcoder-message" field of type #GstTranscoderMessage.
+ * Further fields of the message data are specific to each possible value of
+ * that enumeration.
+ *
+ * Applications can consume the messages asynchronously within their own
+ * event-loop / UI-thread etc. Note that in case the application does not
+ * consume the messages, the bus will accumulate these internally and eventually
+ * fill memory. To avoid that, the bus has to be set "flushing".
+ *
+ * Returns: (transfer full): The transcoder message bus instance
+ *
+ * Since: 1.20
+ */
+GstBus *
+gst_transcoder_get_message_bus (GstTranscoder * self)
{
- GstTranscoderGMainContextSignalDispatcher *self =
- GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
-
- switch (prop_id) {
- case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
- g_value_set_boxed (value, self->application_context);
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- break;
- }
+ return g_object_ref (self->api_bus);
}
-static void
- gst_transcoder_g_main_context_signal_dispatcher_class_init
- (GstTranscoderGMainContextSignalDispatcherClass * klass)
+/**
+ * gst_transcoder_message_get_name:
+ * @message: a #GstTranscoderMessage
+ *
+ * Returns (transfer none): The message name
+ *
+ * Since: 1.20
+ */
+const gchar *
+gst_transcoder_message_get_name (GstTranscoderMessage message)
{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- gobject_class->finalize =
- gst_transcoder_g_main_context_signal_dispatcher_finalize;
- gobject_class->set_property =
- gst_transcoder_g_main_context_signal_dispatcher_set_property;
- gobject_class->get_property =
- gst_transcoder_g_main_context_signal_dispatcher_get_property;
-
- g_main_context_signal_dispatcher_param_specs
- [G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT] =
- g_param_spec_boxed ("application-context", "Application Context",
- "Application GMainContext to dispatch signals to", G_TYPE_MAIN_CONTEXT,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
-
- g_object_class_install_properties (gobject_class,
- G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST,
- g_main_context_signal_dispatcher_param_specs);
+ GEnumClass *enum_class;
+ GEnumValue *enum_value;
+ enum_class = g_type_class_ref (GST_TYPE_TRANSCODER_MESSAGE);
+ enum_value = g_enum_get_value (enum_class, message);
+ g_assert (enum_value != NULL);
+ g_type_class_unref (enum_class);
+ return enum_value->value_name;
}
-static void
- gst_transcoder_g_main_context_signal_dispatcher_init
- (G_GNUC_UNUSED GstTranscoderGMainContextSignalDispatcher * self)
-{
-}
-typedef struct
-{
- void (*emitter) (gpointer data);
- gpointer data;
- GDestroyNotify destroy;
-} GMainContextSignalDispatcherData;
+#define PARSE_MESSAGE_FIELD(msg, field, value_type, value) G_STMT_START { \
+ const GstStructure *data = NULL; \
+ g_return_if_fail (gst_transcoder_is_transcoder_message (msg)); \
+ data = gst_message_get_structure (msg); \
+ if (!gst_structure_get (data, field, value_type, value, NULL)) { \
+ g_error ("Could not parse field from structure: %s", field); \
+ } \
+} G_STMT_END
-static gboolean
-g_main_context_signal_dispatcher_dispatch_gsourcefunc (gpointer user_data)
+/**
+ * gst_transcoder_is_transcoder_message:
+ * @msg: A #GstMessage
+ *
+ * Returns: A #gboolean indicating whether the passes message represents a #GstTranscoder message or not.
+ *
+ * Since: 1.20
+ */
+gboolean
+gst_transcoder_is_transcoder_message (GstMessage * msg)
{
- GMainContextSignalDispatcherData *data = user_data;
+ const GstStructure *data = NULL;
+ g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE);
- data->emitter (data->data);
+ data = gst_message_get_structure (msg);
+ g_return_val_if_fail (data, FALSE);
- return G_SOURCE_REMOVE;
+ return g_str_equal (gst_structure_get_name (data),
+ GST_TRANSCODER_MESSAGE_DATA);
}
-static void
-g_main_context_signal_dispatcher_dispatch_destroy (gpointer user_data)
+/**
+ * gst_transcoder_message_parse_duration:
+ * @msg: A #GstMessage
+ * @duration: (out): the resulting duration
+ *
+ * Parse the given duration @msg and extract the corresponding #GstClockTime
+ *
+ * Since: 1.20
+ */
+void
+gst_transcoder_message_parse_duration (GstMessage * msg,
+ GstClockTime * duration)
{
- GMainContextSignalDispatcherData *data = user_data;
-
- if (data->destroy)
- data->destroy (data->data);
- g_free (data);
+ PARSE_MESSAGE_FIELD (msg, GST_TRANSCODER_MESSAGE_DATA_DURATION,
+ GST_TYPE_CLOCK_TIME, duration);
}
-/* *INDENT-OFF* */
-static void
-gst_transcoder_g_main_context_signal_dispatcher_dispatch (GstTranscoderSignalDispatcher * iface,
- G_GNUC_UNUSED GstTranscoder * transcoder, void (*emitter) (gpointer data),
- gpointer data, GDestroyNotify destroy)
+/**
+ * gst_transcoder_message_parse_position:
+ * @msg: A #GstMessage
+ * @position: (out): the resulting position
+ *
+ * Parse the given position @msg and extract the corresponding #GstClockTime
+ *
+ * Since: 1.20
+ */
+void
+gst_transcoder_message_parse_position (GstMessage * msg,
+ GstClockTime * position)
{
- GstTranscoderGMainContextSignalDispatcher *self =
- GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (iface);
- GMainContextSignalDispatcherData *gsourcefunc_data =
- g_new0 (GMainContextSignalDispatcherData, 1);
-
- gsourcefunc_data->emitter = emitter;
- gsourcefunc_data->data = data;
- gsourcefunc_data->destroy = destroy;
-
- g_main_context_invoke_full (self->application_context,
- G_PRIORITY_DEFAULT, g_main_context_signal_dispatcher_dispatch_gsourcefunc,
- gsourcefunc_data, g_main_context_signal_dispatcher_dispatch_destroy);
+ PARSE_MESSAGE_FIELD (msg, GST_TRANSCODER_MESSAGE_DATA_POSITION,
+ GST_TYPE_CLOCK_TIME, position);
}
-static void
-gst_transcoder_g_main_context_signal_dispatcher_interface_init (GstTranscoderSignalDispatcherInterface * iface)
+/**
+ * gst_transcoder_message_parse_error:
+ * @msg: A #GstMessage
+ * @error: (out): the resulting error
+ * @details: (out): (transfer none): A GstStructure containing extra details about the error
+ *
+ * Parse the given error @msg and extract the corresponding #GError
+ *
+ * Since: 1.20
+ */
+void
+gst_transcoder_message_parse_error (GstMessage * msg, GError * error,
+ GstStructure ** details)
{
- iface->dispatch = gst_transcoder_g_main_context_signal_dispatcher_dispatch;
+ PARSE_MESSAGE_FIELD (msg, GST_TRANSCODER_MESSAGE_DATA_ERROR, G_TYPE_ERROR,
+ error);
+ PARSE_MESSAGE_FIELD (msg, GST_TRANSCODER_MESSAGE_DATA_ISSUE_DETAILS,
+ GST_TYPE_STRUCTURE, details);
}
-/* *INDENT-ON* */
/**
- * gst_transcoder_g_main_context_signal_dispatcher_new:
- * @application_context: (allow-none): GMainContext to use or %NULL
+ * gst_transcoder_message_parse_warning:
+ * @msg: A #GstMessage
+ * @error: (out): the resulting warning
+ * @details: (out): (transfer none): A GstStructure containing extra details about the warning
+ *
+ * Parse the given error @msg and extract the corresponding #GError warning
*
- * Returns: (transfer full):
+ * Since: 1.20
*/
-GstTranscoderSignalDispatcher *
-gst_transcoder_g_main_context_signal_dispatcher_new (GMainContext *
- application_context)
+void
+gst_transcoder_message_parse_warning (GstMessage * msg, GError * error,
+ GstStructure ** details)
{
- return g_object_new (GST_TYPE_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER,
- "application-context", application_context, NULL);
+ PARSE_MESSAGE_FIELD (msg, GST_TRANSCODER_MESSAGE_DATA_WARNING, G_TYPE_ERROR,
+ error);
+ PARSE_MESSAGE_FIELD (msg, GST_TRANSCODER_MESSAGE_DATA_ISSUE_DETAILS,
+ GST_TYPE_STRUCTURE, details);
}
diff --git a/gst-libs/gst/transcoder/gsttranscoder.h b/gst-libs/gst/transcoder/gsttranscoder.h
index ccc3dd7fa..dcd22860d 100644
--- a/gst-libs/gst/transcoder/gsttranscoder.h
+++ b/gst-libs/gst/transcoder/gsttranscoder.h
@@ -12,9 +12,6 @@
G_BEGIN_DECLS
-typedef struct _GstTranscoderSignalDispatcher GstTranscoderSignalDispatcher;
-typedef struct _GstTranscoderSignalDispatcherInterface GstTranscoderSignalDispatcherInterface;
-
/*********** Error definitions ************/
#define GST_TRANSCODER_ERROR (gst_transcoder_error_quark ())
@@ -31,6 +28,51 @@ GQuark gst_transcoder_error_quark (void);
GST_TRANSCODER_API
const gchar * gst_transcoder_error_get_name (GstTranscoderError error);
+/*********** Messages types definitions ************/
+
+/**
+ * GstTranscoderMessage:
+ * @GST_TRANSCODER_MESSAGE_POSITION_UPDATED: Sink position changed
+ * @GST_TRANSCODER_MESSAGE_DURATION_CHANGED: Duration of stream changed
+ * @GST_TRANSCODER_MESSAGE_DONE: Transcoding is done
+ * @GST_TRANSCODER_MESSAGE_ERROR: Message contains an error
+ * @GST_TRANSCODER_MESSAGE_WARNING: Message contains an error
+ *
+ * Types of messages that will be posted on the transcoder API bus.
+ *
+ * See also #gst_transcoder_get_message_bus()
+ *
+ * Since: 1.20
+ */
+typedef enum
+{
+ GST_TRANSCODER_MESSAGE_POSITION_UPDATED,
+ GST_TRANSCODER_MESSAGE_DURATION_CHANGED,
+ GST_TRANSCODER_MESSAGE_DONE,
+ GST_TRANSCODER_MESSAGE_ERROR,
+ GST_TRANSCODER_MESSAGE_WARNING,
+} GstTranscoderMessage;
+
+GST_TRANSCODER_API
+gboolean gst_transcoder_is_transcoder_message (GstMessage * msg);
+
+GST_TRANSCODER_API
+const gchar * gst_transcoder_message_get_name (GstTranscoderMessage message);
+
+GST_TRANSCODER_API
+void gst_transcoder_message_parse_position (GstMessage * msg, GstClockTime * position);
+
+GST_TRANSCODER_API
+void gst_transcoder_message_parse_duration (GstMessage * msg, GstClockTime * duration);
+
+GST_TRANSCODER_API
+void gst_transcoder_message_parse_error (GstMessage * msg, GError * error, GstStructure ** details);
+
+GST_TRANSCODER_API
+void gst_transcoder_message_parse_warning (GstMessage * msg, GError * error, GstStructure ** details);
+
+
+
/*********** GstTranscoder definition ************/
#define GST_TYPE_TRANSCODER (gst_transcoder_get_type ())
@@ -50,22 +92,24 @@ GstTranscoder * gst_transcoder_new (const gchar * source_
GST_TRANSCODER_API
GstTranscoder * gst_transcoder_new_full (const gchar * source_uri,
const gchar * dest_uri,
- GstEncodingProfile *profile,
- GstTranscoderSignalDispatcher *signal_dispatcher);
+ GstEncodingProfile * profile);
GST_TRANSCODER_API
-gboolean gst_transcoder_run (GstTranscoder *self,
+gboolean gst_transcoder_run (GstTranscoder * self,
GError ** error);
GST_TRANSCODER_API
-void gst_transcoder_set_cpu_usage (GstTranscoder *self,
+GstBus * gst_transcoder_get_message_bus (GstTranscoder * transcoder);
+
+GST_TRANSCODER_API
+void gst_transcoder_set_cpu_usage (GstTranscoder * self,
gint cpu_usage);
GST_TRANSCODER_API
-void gst_transcoder_run_async (GstTranscoder *self);
+void gst_transcoder_run_async (GstTranscoder * self);
GST_TRANSCODER_API
-void gst_transcoder_set_position_update_interval (GstTranscoder *self,
+void gst_transcoder_set_position_update_interval (GstTranscoder * self,
guint interval);
GST_TRANSCODER_API
@@ -75,7 +119,7 @@ GST_TRANSCODER_API
gchar * gst_transcoder_get_dest_uri (GstTranscoder * self);
GST_TRANSCODER_API
-guint gst_transcoder_get_position_update_interval (GstTranscoder *self);
+guint gst_transcoder_get_position_update_interval (GstTranscoder * self);
GST_TRANSCODER_API
GstClockTime gst_transcoder_get_position (GstTranscoder * self);
@@ -92,43 +136,7 @@ GST_TRANSCODER_API
void gst_transcoder_set_avoid_reencoding (GstTranscoder * self,
gboolean avoid_reencoding);
-
-/****************** Signal dispatcher *******************************/
-
-#define GST_TYPE_TRANSCODER_SIGNAL_DISPATCHER (gst_transcoder_signal_dispatcher_get_type ())
-#define GST_TRANSCODER_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TRANSCODER_SIGNAL_DISPATCHER, GstTranscoderSignalDispatcher))
-#define GST_IS_TRANSCODER_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TRANSCODER_SIGNAL_DISPATCHER))
-#define GST_TRANSCODER_SIGNAL_DISPATCHER_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), GST_TYPE_TRANSCODER_SIGNAL_DISPATCHER, GstTranscoderSignalDispatcherInterface))
-
-struct _GstTranscoderSignalDispatcherInterface {
- GTypeInterface parent_iface;
-
- void (*dispatch) (GstTranscoderSignalDispatcher * self,
- GstTranscoder * transcoder,
- void (*emitter) (gpointer data),
- gpointer data,
- GDestroyNotify destroy);
-};
-
-typedef struct _GstTranscoderGMainContextSignalDispatcher GstTranscoderGMainContextSignalDispatcher;
-typedef struct _GstTranscoderGMainContextSignalDispatcherClass GstTranscoderGMainContextSignalDispatcherClass;
-
-GST_TRANSCODER_API
-GType gst_transcoder_signal_dispatcher_get_type (void);
-
-#define GST_TYPE_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (gst_transcoder_g_main_context_signal_dispatcher_get_type ())
-#define GST_IS_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER))
-#define GST_IS_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER))
-#define GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GstTranscoderGMainContextSignalDispatcherClass))
-#define GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GstTranscoderGMainContextSignalDispatcher))
-#define GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GstTranscoderGMainContextSignalDispatcherClass))
-#define GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER_CAST(obj) ((GstTranscoderGMainContextSignalDispatcher*)(obj))
-
-GST_TRANSCODER_API
-GType gst_transcoder_g_main_context_signal_dispatcher_get_type (void);
-
-GST_TRANSCODER_API
-GstTranscoderSignalDispatcher * gst_transcoder_g_main_context_signal_dispatcher_new (GMainContext * application_context);
+#include "gsttranscoder-signal-adapter.h"
G_END_DECLS
diff --git a/gst-libs/gst/transcoder/meson.build b/gst-libs/gst/transcoder/meson.build
index 4381efa9e..b6c54983f 100644
--- a/gst-libs/gst/transcoder/meson.build
+++ b/gst-libs/gst/transcoder/meson.build
@@ -1,5 +1,5 @@
-sources = files(['gsttranscoder.c'])
-headers = files(['gsttranscoder.h', 'transcoder-prelude.h'])
+sources = files(['gsttranscoder.c', 'gsttranscoder-signal-adapter.c'])
+headers = files(['gsttranscoder.h', 'transcoder-prelude.h', 'gsttranscoder-signal-adapter.h'])
install_headers(headers, subdir : 'gstreamer-' + api_version + '/gst/transcoder')
diff --git a/tools/gst-transcoder.c b/tools/gst-transcoder.c
index d805c7649..3d1bc83d2 100644
--- a/tools/gst-transcoder.c
+++ b/tools/gst-transcoder.c
@@ -282,6 +282,7 @@ main (int argc, char *argv[])
GError *err = NULL;
GstTranscoder *transcoder;
GOptionContext *ctx;
+ GstTranscoderSignalAdapter *signal_adapter;
Settings settings = {
.cpu_usage = 100,
.rate = -1,
@@ -371,19 +372,22 @@ main (int argc, char *argv[])
}
transcoder = gst_transcoder_new_full (settings.src_uri, settings.dest_uri,
- settings.profile, NULL);
+ settings.profile);
gst_transcoder_set_avoid_reencoding (transcoder, TRUE);
-
gst_transcoder_set_cpu_usage (transcoder, settings.cpu_usage);
- g_signal_connect (transcoder, "position-updated",
- G_CALLBACK (position_updated_cb), NULL);
- g_signal_connect (transcoder, "warning", G_CALLBACK (_warning_cb), NULL);
- g_signal_connect (transcoder, "error", G_CALLBACK (_error_cb), NULL);
- g_assert (transcoder);
+ signal_adapter = gst_transcoder_signal_adapter_new (transcoder, NULL);
+ g_signal_connect_swapped (signal_adapter, "position-updated",
+ G_CALLBACK (position_updated_cb), transcoder);
+ g_signal_connect_swapped (signal_adapter, "warning", G_CALLBACK (_warning_cb),
+ transcoder);
+ g_signal_connect_swapped (signal_adapter, "error", G_CALLBACK (_error_cb),
+ transcoder);
+
ok ("Starting transcoding...");
gst_transcoder_run (transcoder, &err);
+ g_object_unref (signal_adapter);
if (!err)
ok ("\nDONE.");