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>
This commit is contained in:
Thibault Saunier 2020-11-25 22:25:28 -03:00 committed by GStreamer Merge Bot
parent 7cf6e4d8f2
commit 984f0c2d2f
7 changed files with 735 additions and 512 deletions

View file

@ -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"

View file

@ -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);
}

View file

@ -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

View file

@ -28,6 +28,7 @@
*/ */
#include "gsttranscoder.h" #include "gsttranscoder.h"
#include "gsttranscoder-message-private.h"
GST_DEBUG_CATEGORY_STATIC (gst_transcoder_debug); GST_DEBUG_CATEGORY_STATIC (gst_transcoder_debug);
#define GST_CAT_DEFAULT gst_transcoder_debug #define GST_CAT_DEFAULT gst_transcoder_debug
@ -52,7 +53,6 @@ gst_transcoder_error_quark (void)
enum enum
{ {
PROP_0, PROP_0,
PROP_SIGNAL_DISPATCHER,
PROP_SRC_URI, PROP_SRC_URI,
PROP_DEST_URI, PROP_DEST_URI,
PROP_PROFILE, PROP_PROFILE,
@ -64,22 +64,10 @@ enum
PROP_LAST PROP_LAST
}; };
enum
{
SIGNAL_POSITION_UPDATED,
SIGNAL_DURATION_CHANGED,
SIGNAL_DONE,
SIGNAL_ERROR,
SIGNAL_WARNING,
SIGNAL_LAST
};
struct _GstTranscoder struct _GstTranscoder
{ {
GstObject parent; GstObject parent;
GstTranscoderSignalDispatcher *signal_dispatcher;
GstEncodingProfile *profile; GstEncodingProfile *profile;
gchar *source_uri; gchar *source_uri;
gchar *dest_uri; gchar *dest_uri;
@ -99,6 +87,8 @@ struct _GstTranscoder
gint wanted_cpu_usage; gint wanted_cpu_usage;
GstClockTime last_duration; GstClockTime last_duration;
GstBus *api_bus;
}; };
struct _GstTranscoderClass struct _GstTranscoderClass
@ -106,15 +96,9 @@ struct _GstTranscoderClass
GstObjectClass parent_class; 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 #define parent_class gst_transcoder_parent_class
G_DEFINE_TYPE (GstTranscoder, gst_transcoder, GST_TYPE_OBJECT); G_DEFINE_TYPE (GstTranscoder, gst_transcoder, GST_TYPE_OBJECT);
static guint signals[SIGNAL_LAST] = { 0, };
static GParamSpec *param_specs[PROP_LAST] = { NULL, }; static GParamSpec *param_specs[PROP_LAST] = { NULL, };
static void gst_transcoder_dispose (GObject * object); static void gst_transcoder_dispose (GObject * object);
@ -162,6 +146,7 @@ gst_transcoder_init (GstTranscoder * self)
self->context = g_main_context_new (); self->context = g_main_context_new ();
self->loop = g_main_loop_new (self->context, FALSE); self->loop = g_main_loop_new (self->context, FALSE);
self->api_bus = gst_bus_new ();
self->wanted_cpu_usage = 100; self->wanted_cpu_usage = 100;
self->position_update_interval_ms = DEFAULT_POSITION_UPDATE_INTERVAL_MS; 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->finalize = gst_transcoder_finalize;
gobject_class->constructed = gst_transcoder_constructed; 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] = param_specs[PROP_SRC_URI] =
g_param_spec_string ("src-uri", "URI", "Source URI", DEFAULT_URI, g_param_spec_string ("src-uri", "URI", "Source URI", DEFAULT_URI,
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); 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); DEFAULT_AVOID_REENCODING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_properties (gobject_class, PROP_LAST, param_specs); 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 static void
@ -292,8 +246,6 @@ gst_transcoder_finalize (GObject * object)
g_free (self->source_uri); g_free (self->source_uri);
g_free (self->dest_uri); g_free (self->dest_uri);
if (self->signal_dispatcher)
g_object_unref (self->signal_dispatcher);
g_cond_clear (&self->cond); g_cond_clear (&self->cond);
G_OBJECT_CLASS (parent_class)->finalize (object); 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); GstTranscoder *self = GST_TRANSCODER (object);
switch (prop_id) { switch (prop_id) {
case PROP_SIGNAL_DISPATCHER:
self->signal_dispatcher = g_value_dup_object (value);
break;
case PROP_SRC_URI:{ case PROP_SRC_URI:{
GST_OBJECT_LOCK (self); GST_OBJECT_LOCK (self);
g_free (self->source_uri); 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 static gboolean
main_loop_running_cb (gpointer user_data) main_loop_running_cb (gpointer user_data)
{ {
@ -455,32 +432,6 @@ main_loop_running_cb (gpointer user_data)
return G_SOURCE_REMOVE; 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 static gboolean
tick_cb (gpointer user_data) 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)); GST_LOG_OBJECT (self, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID, api_bus_post_message (self, GST_TRANSCODER_MESSAGE_POSITION_UPDATED,
signals[SIGNAL_POSITION_UPDATED], 0, NULL, NULL, NULL) != 0) { GST_TRANSCODER_MESSAGE_DATA_POSITION, GST_TYPE_CLOCK_TIME, position,
PositionUpdatedSignalData *data = g_new0 (PositionUpdatedSignalData, 1); NULL);
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);
}
return G_SOURCE_CONTINUE; return G_SOURCE_CONTINUE;
} }
@ -537,58 +481,6 @@ remove_tick_source (GstTranscoder * self)
self->tick_source = NULL; 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 static void
dump_dot_file (GstTranscoder * self, const gchar * name) dump_dot_file (GstTranscoder * self, const gchar * name)
{ {
@ -602,33 +494,6 @@ dump_dot_file (GstTranscoder * self, const gchar * name)
g_free (full_name); g_free (full_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 static void
error_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data) error_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
{ {
@ -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-element-name", G_TYPE_STRING, "name",
"msg-source-type", G_TYPE_GTYPE, G_OBJECT_TYPE (msg->src), "msg-source-type", G_TYPE_GTYPE, G_OBJECT_TYPE (msg->src),
"msg-error", G_TYPE_STRING, message, NULL); "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); gst_structure_free (details);
g_clear_error (&err); g_clear_error (&err);
@ -695,8 +564,13 @@ warning_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
transcoder_err = transcoder_err =
g_error_new_literal (GST_TRANSCODER_ERROR, GST_TRANSCODER_ERROR_FAILED, g_error_new_literal (GST_TRANSCODER_ERROR, GST_TRANSCODER_ERROR_FAILED,
full_message); 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_clear_error (&err);
g_free (debug); g_free (debug);
g_free (name); g_free (name);
@ -704,12 +578,6 @@ warning_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
g_free (message); g_free (message);
} }
static void
eos_dispatch (gpointer user_data)
{
g_signal_emit (user_data, signals[SIGNAL_DONE], 0);
}
static void static void
eos_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg, eos_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
gpointer user_data) gpointer user_data)
@ -723,11 +591,7 @@ eos_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
tick_cb (self); tick_cb (self);
remove_tick_source (self); remove_tick_source (self);
if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID, api_bus_post_message (self, GST_TRANSCODER_MESSAGE_DONE, NULL, NULL);
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);
}
self->is_eos = TRUE; 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) if (state_ret != GST_STATE_CHANGE_FAILURE)
state_ret = gst_element_set_state (self->transcodebin, GST_STATE_PLAYING); state_ret = gst_element_set_state (self->transcodebin, GST_STATE_PLAYING);
if (state_ret == GST_STATE_CHANGE_FAILURE) if (state_ret == GST_STATE_CHANGE_FAILURE) {
emit_error (self, g_error_new (GST_TRANSCODER_ERROR, GError *err = g_error_new (GST_TRANSCODER_ERROR,
GST_TRANSCODER_ERROR_FAILED, "Failed to handle clock loss"), GST_TRANSCODER_ERROR_FAILED, "Failed to handle clock loss");
NULL); api_bus_post_message (self, GST_TRANSCODER_MESSAGE_ERROR,
} GST_TRANSCODER_MESSAGE_DATA_ERROR, G_TYPE_ERROR, err, NULL);
} g_error_free (err);
}
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);
} }
} }
@ -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, if (gst_element_query_duration (self->transcodebin, GST_FORMAT_TIME,
&duration)) { &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; self->target_state = state;
state_ret = gst_element_set_state (self->transcodebin, state); state_ret = gst_element_set_state (self->transcodebin, state);
if (state_ret == GST_STATE_CHANGE_FAILURE) if (state_ret == GST_STATE_CHANGE_FAILURE) {
emit_error (self, g_error_new (GST_TRANSCODER_ERROR, GError *err = g_error_new (GST_TRANSCODER_ERROR,
GST_TRANSCODER_ERROR_FAILED, GST_TRANSCODER_ERROR_FAILED,
"Failed to change to requested state %s", "Failed to change to requested state %s",
gst_element_state_get_name (state)), NULL); 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 static void
@ -1030,7 +860,7 @@ gst_transcoder_new (const gchar * source_uri,
profile = create_encoding_profile (encoding_profile); 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 * @profile: The #GstEncodingProfile defining the output format
* have a look at the #GstEncodingProfile documentation to find more * have a look at the #GstEncodingProfile documentation to find more
* about the serialization format. * about the serialization format.
* @signal_dispatcher: The #GstTranscoderSignalDispatcher to be used
* to dispatch the various signals.
* *
* Returns: a new #GstTranscoder instance * Returns: a new #GstTranscoder instance
*/ */
GstTranscoder * GstTranscoder *
gst_transcoder_new_full (const gchar * source_uri, gst_transcoder_new_full (const gchar * source_uri,
const gchar * dest_uri, GstEncodingProfile * profile, const gchar * dest_uri, GstEncodingProfile * profile)
GstTranscoderSignalDispatcher * signal_dispatcher)
{ {
static GOnce once = G_ONCE_INIT; 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); g_return_val_if_fail (dest_uri, NULL);
return g_object_new (GST_TYPE_TRANSCODER, "src-uri", source_uri, return g_object_new (GST_TYPE_TRANSCODER, "src-uri", source_uri,
"dest-uri", dest_uri, "profile", profile, "dest-uri", dest_uri, "profile", profile, NULL);
"signal-dispatcher", signal_dispatcher, NULL);
} }
typedef struct typedef struct
@ -1069,8 +895,7 @@ typedef struct
} RunSyncData; } RunSyncData;
static void static void
_error_cb (GstTranscoder * self, GError * error, GstStructure * details, _error_cb (RunSyncData * data, GError * error, GstStructure * details)
RunSyncData * data)
{ {
if (data->error == NULL) if (data->error == NULL)
g_propagate_error (&data->error, error); g_propagate_error (&data->error, error);
@ -1082,7 +907,7 @@ _error_cb (GstTranscoder * self, GError * error, GstStructure * details,
} }
static void static void
_done_cb (GstTranscoder * self, RunSyncData * data) _done_cb (RunSyncData * data)
{ {
if (data->loop) { if (data->loop) {
g_main_loop_quit (data->loop); g_main_loop_quit (data->loop);
@ -1103,17 +928,20 @@ gboolean
gst_transcoder_run (GstTranscoder * self, GError ** error) gst_transcoder_run (GstTranscoder * self, GError ** error)
{ {
RunSyncData data = { 0, }; RunSyncData data = { 0, };
GstTranscoderSignalAdapter *signal_adapter =
gst_transcoder_signal_adapter_new (self, NULL);
data.loop = g_main_loop_new (NULL, FALSE); data.loop = g_main_loop_new (NULL, FALSE);
g_signal_connect (self, "error", G_CALLBACK (_error_cb), &data); g_signal_connect_swapped (signal_adapter, "error", G_CALLBACK (_error_cb),
g_signal_connect (self, "done", G_CALLBACK (_done_cb), &data); &data);
g_signal_connect_swapped (signal_adapter, "done", G_CALLBACK (_done_cb),
&data);
gst_transcoder_run_async (self); gst_transcoder_run_async (self);
if (!data.error) if (!data.error)
g_main_loop_run (data.loop); g_main_loop_run (data.loop);
g_signal_handlers_disconnect_by_func (self, _error_cb, &data); g_object_unref (signal_adapter);
g_signal_handlers_disconnect_by_func (self, _done_cb, &data);
if (data.error) { if (data.error) {
if (error) if (error)
@ -1143,8 +971,12 @@ gst_transcoder_run_async (GstTranscoder * self)
GST_DEBUG_OBJECT (self, "Play"); GST_DEBUG_OBJECT (self, "Play");
if (!self->profile) { if (!self->profile) {
emit_error (self, g_error_new (GST_TRANSCODER_ERROR, GError *err = g_error_new (GST_TRANSCODER_ERROR,
GST_TRANSCODER_ERROR_FAILED, "No \"profile\" provided"), NULL); 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; return;
} }
@ -1153,8 +985,12 @@ gst_transcoder_run_async (GstTranscoder * self)
state_ret = gst_element_set_state (self->transcodebin, GST_STATE_PLAYING); state_ret = gst_element_set_state (self->transcodebin, GST_STATE_PLAYING);
if (state_ret == GST_STATE_CHANGE_FAILURE) { if (state_ret == GST_STATE_CHANGE_FAILURE) {
emit_error (self, g_error_new (GST_TRANSCODER_ERROR, GError *err = g_error_new (GST_TRANSCODER_ERROR,
GST_TRANSCODER_ERROR_FAILED, "Could not start transcoding"), NULL); 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; return;
} else if (state_ret == GST_STATE_CHANGE_NO_PREROLL) { } else if (state_ret == GST_STATE_CHANGE_NO_PREROLL) {
self->is_live = TRUE; self->is_live = TRUE;
@ -1372,212 +1208,154 @@ gst_transcoder_error_get_name (GstTranscoderError error)
return NULL; return NULL;
} }
G_DEFINE_INTERFACE (GstTranscoderSignalDispatcher, /**
gst_transcoder_signal_dispatcher, G_TYPE_OBJECT); * gst_transcoder_get_message_bus:
* @transcoder: #GstTranscoder instance
static void *
gst_transcoder_signal_dispatcher_default_init (G_GNUC_UNUSED * GstTranscoder API exposes a #GstBus instance which purpose is to provide data
GstTranscoderSignalDispatcherInterface * iface) * 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)
{ {
return g_object_ref (self->api_bus);
} }
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)
{
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;
}
}
static void
gst_transcoder_g_main_context_signal_dispatcher_class_init
(GstTranscoderGMainContextSignalDispatcherClass * klass)
{
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);
}
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;
static gboolean
g_main_context_signal_dispatcher_dispatch_gsourcefunc (gpointer user_data)
{
GMainContextSignalDispatcherData *data = user_data;
data->emitter (data->data);
return G_SOURCE_REMOVE;
}
static void
g_main_context_signal_dispatcher_dispatch_destroy (gpointer user_data)
{
GMainContextSignalDispatcherData *data = user_data;
if (data->destroy)
data->destroy (data->data);
g_free (data);
}
/* *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)
{
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);
}
static void
gst_transcoder_g_main_context_signal_dispatcher_interface_init (GstTranscoderSignalDispatcherInterface * iface)
{
iface->dispatch = gst_transcoder_g_main_context_signal_dispatcher_dispatch;
}
/* *INDENT-ON* */
/** /**
* gst_transcoder_g_main_context_signal_dispatcher_new: * gst_transcoder_message_get_name:
* @application_context: (allow-none): GMainContext to use or %NULL * @message: a #GstTranscoderMessage
* *
* Returns: (transfer full): * Returns (transfer none): The message name
*
* Since: 1.20
*/ */
GstTranscoderSignalDispatcher * const gchar *
gst_transcoder_g_main_context_signal_dispatcher_new (GMainContext * gst_transcoder_message_get_name (GstTranscoderMessage message)
application_context)
{ {
return g_object_new (GST_TYPE_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER, GEnumClass *enum_class;
"application-context", application_context, NULL); 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;
}
#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
/**
* 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)
{
const GstStructure *data = NULL;
g_return_val_if_fail (GST_IS_MESSAGE (msg), FALSE);
data = gst_message_get_structure (msg);
g_return_val_if_fail (data, FALSE);
return g_str_equal (gst_structure_get_name (data),
GST_TRANSCODER_MESSAGE_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)
{
PARSE_MESSAGE_FIELD (msg, GST_TRANSCODER_MESSAGE_DATA_DURATION,
GST_TYPE_CLOCK_TIME, duration);
}
/**
* 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)
{
PARSE_MESSAGE_FIELD (msg, GST_TRANSCODER_MESSAGE_DATA_POSITION,
GST_TYPE_CLOCK_TIME, position);
}
/**
* 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)
{
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);
}
/**
* 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
*
* Since: 1.20
*/
void
gst_transcoder_message_parse_warning (GstMessage * msg, GError * error,
GstStructure ** details)
{
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);
} }

View file

@ -12,9 +12,6 @@
G_BEGIN_DECLS G_BEGIN_DECLS
typedef struct _GstTranscoderSignalDispatcher GstTranscoderSignalDispatcher;
typedef struct _GstTranscoderSignalDispatcherInterface GstTranscoderSignalDispatcherInterface;
/*********** Error definitions ************/ /*********** Error definitions ************/
#define GST_TRANSCODER_ERROR (gst_transcoder_error_quark ()) #define GST_TRANSCODER_ERROR (gst_transcoder_error_quark ())
@ -31,6 +28,51 @@ GQuark gst_transcoder_error_quark (void);
GST_TRANSCODER_API GST_TRANSCODER_API
const gchar * gst_transcoder_error_get_name (GstTranscoderError error); 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 ************/ /*********** GstTranscoder definition ************/
#define GST_TYPE_TRANSCODER (gst_transcoder_get_type ()) #define GST_TYPE_TRANSCODER (gst_transcoder_get_type ())
@ -50,22 +92,24 @@ GstTranscoder * gst_transcoder_new (const gchar * source_
GST_TRANSCODER_API GST_TRANSCODER_API
GstTranscoder * gst_transcoder_new_full (const gchar * source_uri, GstTranscoder * gst_transcoder_new_full (const gchar * source_uri,
const gchar * dest_uri, const gchar * dest_uri,
GstEncodingProfile *profile, GstEncodingProfile * profile);
GstTranscoderSignalDispatcher *signal_dispatcher);
GST_TRANSCODER_API GST_TRANSCODER_API
gboolean gst_transcoder_run (GstTranscoder *self, gboolean gst_transcoder_run (GstTranscoder * self,
GError ** error); GError ** error);
GST_TRANSCODER_API 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); gint cpu_usage);
GST_TRANSCODER_API GST_TRANSCODER_API
void gst_transcoder_run_async (GstTranscoder *self); void gst_transcoder_run_async (GstTranscoder * self);
GST_TRANSCODER_API GST_TRANSCODER_API
void gst_transcoder_set_position_update_interval (GstTranscoder *self, void gst_transcoder_set_position_update_interval (GstTranscoder * self,
guint interval); guint interval);
GST_TRANSCODER_API GST_TRANSCODER_API
@ -75,7 +119,7 @@ GST_TRANSCODER_API
gchar * gst_transcoder_get_dest_uri (GstTranscoder * self); gchar * gst_transcoder_get_dest_uri (GstTranscoder * self);
GST_TRANSCODER_API GST_TRANSCODER_API
guint gst_transcoder_get_position_update_interval (GstTranscoder *self); guint gst_transcoder_get_position_update_interval (GstTranscoder * self);
GST_TRANSCODER_API GST_TRANSCODER_API
GstClockTime gst_transcoder_get_position (GstTranscoder * self); GstClockTime gst_transcoder_get_position (GstTranscoder * self);
@ -92,43 +136,7 @@ GST_TRANSCODER_API
void gst_transcoder_set_avoid_reencoding (GstTranscoder * self, void gst_transcoder_set_avoid_reencoding (GstTranscoder * self,
gboolean avoid_reencoding); gboolean avoid_reencoding);
#include "gsttranscoder-signal-adapter.h"
/****************** 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);
G_END_DECLS G_END_DECLS

View file

@ -1,5 +1,5 @@
sources = files(['gsttranscoder.c']) sources = files(['gsttranscoder.c', 'gsttranscoder-signal-adapter.c'])
headers = files(['gsttranscoder.h', 'transcoder-prelude.h']) headers = files(['gsttranscoder.h', 'transcoder-prelude.h', 'gsttranscoder-signal-adapter.h'])
install_headers(headers, subdir : 'gstreamer-' + api_version + '/gst/transcoder') install_headers(headers, subdir : 'gstreamer-' + api_version + '/gst/transcoder')

View file

@ -282,6 +282,7 @@ main (int argc, char *argv[])
GError *err = NULL; GError *err = NULL;
GstTranscoder *transcoder; GstTranscoder *transcoder;
GOptionContext *ctx; GOptionContext *ctx;
GstTranscoderSignalAdapter *signal_adapter;
Settings settings = { Settings settings = {
.cpu_usage = 100, .cpu_usage = 100,
.rate = -1, .rate = -1,
@ -371,19 +372,22 @@ main (int argc, char *argv[])
} }
transcoder = gst_transcoder_new_full (settings.src_uri, settings.dest_uri, 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_avoid_reencoding (transcoder, TRUE);
gst_transcoder_set_cpu_usage (transcoder, settings.cpu_usage); 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..."); ok ("Starting transcoding...");
gst_transcoder_run (transcoder, &err); gst_transcoder_run (transcoder, &err);
g_object_unref (signal_adapter);
if (!err) if (!err)
ok ("\nDONE."); ok ("\nDONE.");