mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-20 00:31:13 +00:00
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:
parent
7cf6e4d8f2
commit
984f0c2d2f
7 changed files with 735 additions and 512 deletions
30
gst-libs/gst/transcoder/gsttranscoder-message-private.h
Normal file
30
gst-libs/gst/transcoder/gsttranscoder-message-private.h
Normal 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"
|
342
gst-libs/gst/transcoder/gsttranscoder-signal-adapter.c
Normal file
342
gst-libs/gst/transcoder/gsttranscoder-signal-adapter.c
Normal 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);
|
||||||
|
}
|
61
gst-libs/gst/transcoder/gsttranscoder-signal-adapter.h
Normal file
61
gst-libs/gst/transcoder/gsttranscoder-signal-adapter.h
Normal 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
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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')
|
||||||
|
|
||||||
|
|
|
@ -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.");
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue