3 * Copyright (C) 2014-2015 Sebastian Dröge <sebastian@centricular.com>
4 * Copyright (C) 2015 Thibault Saunier <tsaunier@gnome.org>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
16 * You should have received a copy of the GNU Library General Public
17 * License along with this library; if not, write to the
18 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
23 * SECTION:gsttranscoder
24 * @short_description: High level API to transcode media files
25 * from one format to any other format using the GStreamer framework.
27 * - gst_transcoder_error_quark
30 #include "gsttranscoder.h"
32 GST_DEBUG_CATEGORY_STATIC (gst_transcoder_debug);
33 #define GST_CAT_DEFAULT gst_transcoder_debug
35 #define DEFAULT_URI NULL
36 #define DEFAULT_POSITION GST_CLOCK_TIME_NONE
37 #define DEFAULT_DURATION GST_CLOCK_TIME_NONE
38 #define DEFAULT_POSITION_UPDATE_INTERVAL_MS 100
39 #define DEFAULT_AVOID_REENCODING FALSE
42 gst_transcoder_error_quark (void)
47 quark = g_quark_from_static_string ("gst-transcoder-error-quark");
55 PROP_SIGNAL_DISPATCHER,
62 PROP_POSITION_UPDATE_INTERVAL,
63 PROP_AVOID_REENCODING,
69 SIGNAL_POSITION_UPDATED,
70 SIGNAL_DURATION_CHANGED,
81 GstTranscoderSignalDispatcher *signal_dispatcher;
83 GstEncodingProfile *profile;
89 GMainContext *context;
92 GstElement *transcodebin;
94 GstState target_state, current_state;
95 gboolean is_live, is_eos;
96 GSource *tick_source, *ready_timeout_source;
98 guint position_update_interval_ms;
99 gint wanted_cpu_usage;
101 GstClockTime last_duration;
104 struct _GstTranscoderClass
106 GstObjectClass parent_class;
110 gst_transcoder_signal_dispatcher_dispatch (GstTranscoderSignalDispatcher * self,
111 GstTranscoder * transcoder, void (*emitter) (gpointer data), gpointer data,
112 GDestroyNotify destroy);
114 #define parent_class gst_transcoder_parent_class
115 G_DEFINE_TYPE (GstTranscoder, gst_transcoder, GST_TYPE_OBJECT);
117 static guint signals[SIGNAL_LAST] = { 0, };
118 static GParamSpec *param_specs[PROP_LAST] = { NULL, };
120 static void gst_transcoder_dispose (GObject * object);
121 static void gst_transcoder_finalize (GObject * object);
122 static void gst_transcoder_set_property (GObject * object, guint prop_id,
123 const GValue * value, GParamSpec * pspec);
124 static void gst_transcoder_get_property (GObject * object, guint prop_id,
125 GValue * value, GParamSpec * pspec);
126 static void gst_transcoder_constructed (GObject * object);
128 static gpointer gst_transcoder_main (gpointer data);
130 static gboolean gst_transcoder_set_position_update_interval_internal (gpointer
135 * gst_transcoder_set_cpu_usage:
136 * @self: The GstTranscoder to limit CPU usage on.
137 * @cpu_usage: The percentage of the CPU the process running the transcoder
138 * should try to use. It takes into account the number of cores available.
140 * Sets @cpu_usage as target percentage CPU usage of the process running the
141 * transcoding task. It will modulate the transcoding speed to reach that target
145 gst_transcoder_set_cpu_usage (GstTranscoder * self, gint cpu_usage)
147 GST_OBJECT_LOCK (self);
148 self->wanted_cpu_usage = cpu_usage;
149 if (self->transcodebin)
150 g_object_set (self->transcodebin, "cpu-usage", cpu_usage, NULL);
151 GST_OBJECT_UNLOCK (self);
155 gst_transcoder_init (GstTranscoder * self)
157 GST_TRACE_OBJECT (self, "Initializing");
159 self = gst_transcoder_get_instance_private (self);
161 g_cond_init (&self->cond);
163 self->context = g_main_context_new ();
164 self->loop = g_main_loop_new (self->context, FALSE);
165 self->wanted_cpu_usage = 100;
167 self->position_update_interval_ms = DEFAULT_POSITION_UPDATE_INTERVAL_MS;
169 GST_TRACE_OBJECT (self, "Initialized");
173 gst_transcoder_class_init (GstTranscoderClass * klass)
175 GObjectClass *gobject_class = (GObjectClass *) klass;
177 gobject_class->set_property = gst_transcoder_set_property;
178 gobject_class->get_property = gst_transcoder_get_property;
179 gobject_class->dispose = gst_transcoder_dispose;
180 gobject_class->finalize = gst_transcoder_finalize;
181 gobject_class->constructed = gst_transcoder_constructed;
183 param_specs[PROP_SIGNAL_DISPATCHER] =
184 g_param_spec_object ("signal-dispatcher",
185 "Signal Dispatcher", "Dispatcher for the signals to e.g. event loops",
186 GST_TYPE_TRANSCODER_SIGNAL_DISPATCHER,
187 G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
189 param_specs[PROP_SRC_URI] =
190 g_param_spec_string ("src-uri", "URI", "Source URI", DEFAULT_URI,
191 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
193 param_specs[PROP_DEST_URI] =
194 g_param_spec_string ("dest-uri", "URI", "Source URI", DEFAULT_URI,
195 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
197 param_specs[PROP_PROFILE] =
198 g_param_spec_object ("profile", "Profile",
199 "The GstEncodingProfile to use", GST_TYPE_ENCODING_PROFILE,
200 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
202 param_specs[PROP_POSITION] =
203 g_param_spec_uint64 ("position", "Position", "Current Position",
204 0, G_MAXUINT64, DEFAULT_POSITION,
205 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
207 param_specs[PROP_DURATION] =
208 g_param_spec_uint64 ("duration", "Duration", "Duration",
209 0, G_MAXUINT64, DEFAULT_DURATION,
210 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
212 param_specs[PROP_PIPELINE] =
213 g_param_spec_object ("pipeline", "Pipeline",
214 "GStreamer pipeline that is used",
215 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
217 param_specs[PROP_POSITION_UPDATE_INTERVAL] =
218 g_param_spec_uint ("position-update-interval", "Position update interval",
219 "Interval in milliseconds between two position-updated signals."
220 "Pass 0 to stop updating the position.",
221 0, 10000, DEFAULT_POSITION_UPDATE_INTERVAL_MS,
222 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
225 * GstTranscoder:avoid-reencoding:
227 * See #encodebin:avoid-reencoding
229 param_specs[PROP_AVOID_REENCODING] =
230 g_param_spec_boolean ("avoid-reencoding", "Avoid re-encoding",
231 "Whether to re-encode portions of compatible video streams that lay on segment boundaries",
232 DEFAULT_AVOID_REENCODING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
234 g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
236 signals[SIGNAL_POSITION_UPDATED] =
237 g_signal_new ("position-updated", G_TYPE_FROM_CLASS (klass),
238 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
239 NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
241 signals[SIGNAL_DURATION_CHANGED] =
242 g_signal_new ("duration-changed", G_TYPE_FROM_CLASS (klass),
243 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
244 NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
246 signals[SIGNAL_DONE] =
247 g_signal_new ("done", G_TYPE_FROM_CLASS (klass),
248 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
249 NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
251 signals[SIGNAL_ERROR] =
252 g_signal_new ("error", G_TYPE_FROM_CLASS (klass),
253 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
254 NULL, NULL, G_TYPE_NONE, 2, G_TYPE_ERROR, GST_TYPE_STRUCTURE);
256 signals[SIGNAL_WARNING] =
257 g_signal_new ("warning", G_TYPE_FROM_CLASS (klass),
258 G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
259 NULL, NULL, G_TYPE_NONE, 2, G_TYPE_ERROR, GST_TYPE_STRUCTURE);
263 gst_transcoder_dispose (GObject * object)
265 GstTranscoder *self = GST_TRANSCODER (object);
267 GST_TRACE_OBJECT (self, "Stopping main thread");
270 g_main_loop_quit (self->loop);
272 g_thread_join (self->thread);
275 g_main_loop_unref (self->loop);
278 g_main_context_unref (self->context);
279 self->context = NULL;
283 G_OBJECT_CLASS (parent_class)->dispose (object);
287 gst_transcoder_finalize (GObject * object)
289 GstTranscoder *self = GST_TRANSCODER (object);
291 GST_TRACE_OBJECT (self, "Finalizing");
293 g_free (self->source_uri);
294 g_free (self->dest_uri);
295 if (self->signal_dispatcher)
296 g_object_unref (self->signal_dispatcher);
297 g_cond_clear (&self->cond);
299 G_OBJECT_CLASS (parent_class)->finalize (object);
303 gst_transcoder_constructed (GObject * object)
305 GstTranscoder *self = GST_TRANSCODER (object);
307 GST_TRACE_OBJECT (self, "Constructed");
310 gst_element_factory_make ("uritranscodebin", "uritranscodebin");
312 g_object_set (self->transcodebin, "source-uri", self->source_uri,
313 "dest-uri", self->dest_uri, "profile", self->profile,
314 "cpu-usage", self->wanted_cpu_usage, NULL);
316 GST_OBJECT_LOCK (self);
317 self->thread = g_thread_new ("GstTranscoder", gst_transcoder_main, self);
318 while (!self->loop || !g_main_loop_is_running (self->loop))
319 g_cond_wait (&self->cond, GST_OBJECT_GET_LOCK (self));
320 GST_OBJECT_UNLOCK (self);
322 G_OBJECT_CLASS (parent_class)->constructed (object);
326 gst_transcoder_set_property (GObject * object, guint prop_id,
327 const GValue * value, GParamSpec * pspec)
329 GstTranscoder *self = GST_TRANSCODER (object);
332 case PROP_SIGNAL_DISPATCHER:
333 self->signal_dispatcher = g_value_dup_object (value);
336 GST_OBJECT_LOCK (self);
337 g_free (self->source_uri);
338 self->source_uri = g_value_dup_string (value);
339 GST_DEBUG_OBJECT (self, "Set source_uri=%s", self->source_uri);
340 GST_OBJECT_UNLOCK (self);
344 GST_OBJECT_LOCK (self);
345 g_free (self->dest_uri);
346 self->dest_uri = g_value_dup_string (value);
347 GST_DEBUG_OBJECT (self, "Set dest_uri=%s", self->dest_uri);
348 GST_OBJECT_UNLOCK (self);
351 case PROP_POSITION_UPDATE_INTERVAL:
352 GST_OBJECT_LOCK (self);
353 self->position_update_interval_ms = g_value_get_uint (value);
354 GST_DEBUG_OBJECT (self, "Set position update interval=%u ms",
355 g_value_get_uint (value));
356 GST_OBJECT_UNLOCK (self);
358 gst_transcoder_set_position_update_interval_internal (self);
361 GST_OBJECT_LOCK (self);
362 self->profile = g_value_dup_object (value);
363 GST_OBJECT_UNLOCK (self);
365 case PROP_AVOID_REENCODING:
366 g_object_set (self->transcodebin, "avoid-reencoding",
367 g_value_get_boolean (value), NULL);
370 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
376 gst_transcoder_get_property (GObject * object, guint prop_id,
377 GValue * value, GParamSpec * pspec)
379 GstTranscoder *self = GST_TRANSCODER (object);
383 GST_OBJECT_LOCK (self);
384 g_value_set_string (value, self->source_uri);
385 GST_OBJECT_UNLOCK (self);
388 GST_OBJECT_LOCK (self);
389 g_value_set_string (value, self->dest_uri);
390 GST_OBJECT_UNLOCK (self);
396 position = self->last_duration;
398 gst_element_query_position (self->transcodebin, GST_FORMAT_TIME,
400 g_value_set_uint64 (value, position);
401 GST_TRACE_OBJECT (self, "Returning position=%" GST_TIME_FORMAT,
402 GST_TIME_ARGS (g_value_get_uint64 (value)));
408 gst_element_query_duration (self->transcodebin, GST_FORMAT_TIME,
410 g_value_set_uint64 (value, duration);
411 GST_TRACE_OBJECT (self, "Returning duration=%" GST_TIME_FORMAT,
412 GST_TIME_ARGS (g_value_get_uint64 (value)));
416 g_value_set_object (value, self->transcodebin);
418 case PROP_POSITION_UPDATE_INTERVAL:
419 GST_OBJECT_LOCK (self);
420 g_value_set_uint (value,
421 gst_transcoder_get_position_update_interval (self));
422 GST_OBJECT_UNLOCK (self);
425 GST_OBJECT_LOCK (self);
426 g_value_set_object (value, self->profile);
427 GST_OBJECT_UNLOCK (self);
429 case PROP_AVOID_REENCODING:
431 gboolean avoid_reencoding;
433 g_object_get (self->transcodebin, "avoid-reencoding", &avoid_reencoding,
435 g_value_set_boolean (value, avoid_reencoding);
439 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
445 main_loop_running_cb (gpointer user_data)
447 GstTranscoder *self = GST_TRANSCODER (user_data);
449 GST_TRACE_OBJECT (self, "Main loop running now");
451 GST_OBJECT_LOCK (self);
452 g_cond_signal (&self->cond);
453 GST_OBJECT_UNLOCK (self);
455 return G_SOURCE_REMOVE;
460 GstTranscoder *transcoder;
461 GstClockTime position;
462 } PositionUpdatedSignalData;
465 position_updated_dispatch (gpointer user_data)
467 PositionUpdatedSignalData *data = user_data;
469 if (data->transcoder->target_state >= GST_STATE_PAUSED) {
470 g_signal_emit (data->transcoder, signals[SIGNAL_POSITION_UPDATED], 0,
472 g_object_notify_by_pspec (G_OBJECT (data->transcoder),
473 param_specs[PROP_POSITION]);
478 position_updated_signal_data_free (PositionUpdatedSignalData * data)
480 g_object_unref (data->transcoder);
485 tick_cb (gpointer user_data)
487 GstTranscoder *self = GST_TRANSCODER (user_data);
490 if (self->target_state < GST_STATE_PAUSED)
491 return G_SOURCE_CONTINUE;
493 if (!gst_element_query_position (self->transcodebin, GST_FORMAT_TIME,
495 GST_LOG_OBJECT (self, "Could not query position");
496 return G_SOURCE_CONTINUE;
499 GST_LOG_OBJECT (self, "Position %" GST_TIME_FORMAT, GST_TIME_ARGS (position));
501 if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
502 signals[SIGNAL_POSITION_UPDATED], 0, NULL, NULL, NULL) != 0) {
503 PositionUpdatedSignalData *data = g_new0 (PositionUpdatedSignalData, 1);
505 data->transcoder = g_object_ref (self);
506 data->position = position;
507 gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
508 position_updated_dispatch, data,
509 (GDestroyNotify) position_updated_signal_data_free);
512 return G_SOURCE_CONTINUE;
516 add_tick_source (GstTranscoder * self)
518 if (self->tick_source)
521 if (!self->position_update_interval_ms)
524 self->tick_source = g_timeout_source_new (self->position_update_interval_ms);
525 g_source_set_callback (self->tick_source, (GSourceFunc) tick_cb, self, NULL);
526 g_source_attach (self->tick_source, self->context);
530 remove_tick_source (GstTranscoder * self)
532 if (!self->tick_source)
535 g_source_destroy (self->tick_source);
536 g_source_unref (self->tick_source);
537 self->tick_source = NULL;
542 GstTranscoder *transcoder;
544 GstStructure *details;
548 error_dispatch (gpointer user_data)
550 IssueSignalData *data = user_data;
552 g_signal_emit (data->transcoder, signals[SIGNAL_ERROR], 0, data->err,
557 free_issue_signal_data (IssueSignalData * data)
559 g_object_unref (data->transcoder);
561 gst_structure_free (data->details);
562 g_clear_error (&data->err);
567 emit_error (GstTranscoder * self, GError * err, const GstStructure * details)
569 if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
570 signals[SIGNAL_ERROR], 0, NULL, NULL, NULL) != 0) {
571 IssueSignalData *data = g_new0 (IssueSignalData, 1);
573 data->transcoder = g_object_ref (self);
574 data->err = g_error_copy (err);
576 data->details = gst_structure_copy (details);
577 gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
578 error_dispatch, data, (GDestroyNotify) free_issue_signal_data);
583 remove_tick_source (self);
585 self->target_state = GST_STATE_NULL;
586 self->current_state = GST_STATE_NULL;
587 self->is_live = FALSE;
588 self->is_eos = FALSE;
589 gst_element_set_state (self->transcodebin, GST_STATE_NULL);
593 dump_dot_file (GstTranscoder * self, const gchar * name)
597 full_name = g_strdup_printf ("gst-transcoder.%p.%s", self, name);
599 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS (GST_BIN (self->transcodebin),
600 GST_DEBUG_GRAPH_SHOW_ALL, full_name);
606 warning_dispatch (gpointer user_data)
608 IssueSignalData *data = user_data;
610 g_signal_emit (data->transcoder, signals[SIGNAL_WARNING], 0, data->err,
615 emit_warning (GstTranscoder * self, GError * err, const GstStructure * details)
617 if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
618 signals[SIGNAL_WARNING], 0, NULL, NULL, NULL) != 0) {
619 IssueSignalData *data = g_new0 (IssueSignalData, 1);
621 data->transcoder = g_object_ref (self);
622 data->err = g_error_copy (err);
624 data->details = gst_structure_copy (details);
625 gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
626 warning_dispatch, data, (GDestroyNotify) free_issue_signal_data);
633 error_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
636 GstTranscoder *self = GST_TRANSCODER (user_data);
637 gchar *name, *debug, *message;
638 GstStructure *details = NULL;
640 dump_dot_file (self, "error");
642 gst_message_parse_error (msg, &err, &debug);
643 gst_message_parse_error_details (msg, (const GstStructure **) &details);
646 details = gst_structure_new_empty ("details");
648 details = gst_structure_copy (details);
650 name = gst_object_get_path_string (msg->src);
651 message = gst_error_get_message (err->domain, err->code);
653 gst_structure_set (details, "debug", G_TYPE_STRING, debug,
654 "msg-source-element-name", G_TYPE_STRING, "name",
655 "msg-source-type", G_TYPE_GTYPE, G_OBJECT_TYPE (msg->src),
656 "msg-error", G_TYPE_STRING, message, NULL);
657 emit_error (self, g_error_copy (err), details);
659 gst_structure_free (details);
660 g_clear_error (&err);
667 warning_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
669 GstTranscoder *self = GST_TRANSCODER (user_data);
670 GError *err, *transcoder_err;
671 gchar *name, *debug, *message, *full_message;
672 const GstStructure *details = NULL;
674 dump_dot_file (self, "warning");
676 gst_message_parse_warning (msg, &err, &debug);
677 gst_message_parse_warning_details (msg, &details);
679 name = gst_object_get_path_string (msg->src);
680 message = gst_error_get_message (err->domain, err->code);
684 g_strdup_printf ("Warning from element %s: %s\n%s\n%s", name, message,
685 err->message, debug);
688 g_strdup_printf ("Warning from element %s: %s\n%s", name, message,
691 GST_WARNING_OBJECT (self, "WARNING: from element %s: %s", name, err->message);
693 GST_WARNING_OBJECT (self, "Additional debug info: %s", debug);
696 g_error_new_literal (GST_TRANSCODER_ERROR, GST_TRANSCODER_ERROR_FAILED,
698 emit_warning (self, transcoder_err, details);
700 g_clear_error (&err);
703 g_free (full_message);
708 eos_dispatch (gpointer user_data)
710 g_signal_emit (user_data, signals[SIGNAL_DONE], 0);
714 eos_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
717 GstTranscoder *self = GST_TRANSCODER (user_data);
719 GST_DEBUG_OBJECT (self, "End of stream");
721 gst_element_query_duration (self->transcodebin, GST_FORMAT_TIME,
722 (gint64 *) & self->last_duration);
724 remove_tick_source (self);
726 if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
727 signals[SIGNAL_DONE], 0, NULL, NULL, NULL) != 0) {
728 gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
729 eos_dispatch, g_object_ref (self), (GDestroyNotify) g_object_unref);
735 clock_lost_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
738 GstTranscoder *self = GST_TRANSCODER (user_data);
739 GstStateChangeReturn state_ret;
741 GST_DEBUG_OBJECT (self, "Clock lost");
742 if (self->target_state >= GST_STATE_PLAYING) {
743 state_ret = gst_element_set_state (self->transcodebin, GST_STATE_PAUSED);
744 if (state_ret != GST_STATE_CHANGE_FAILURE)
745 state_ret = gst_element_set_state (self->transcodebin, GST_STATE_PLAYING);
747 if (state_ret == GST_STATE_CHANGE_FAILURE)
748 emit_error (self, g_error_new (GST_TRANSCODER_ERROR,
749 GST_TRANSCODER_ERROR_FAILED, "Failed to handle clock loss"),
756 GstTranscoder *transcoder;
757 GstClockTime duration;
758 } DurationChangedSignalData;
761 duration_changed_dispatch (gpointer user_data)
763 DurationChangedSignalData *data = user_data;
765 if (data->transcoder->target_state >= GST_STATE_PAUSED) {
766 g_signal_emit (data->transcoder, signals[SIGNAL_DURATION_CHANGED], 0,
768 g_object_notify_by_pspec (G_OBJECT (data->transcoder),
769 param_specs[PROP_DURATION]);
774 duration_changed_signal_data_free (DurationChangedSignalData * data)
776 g_object_unref (data->transcoder);
781 emit_duration_changed (GstTranscoder * self, GstClockTime duration)
783 GST_DEBUG_OBJECT (self, "Duration changed %" GST_TIME_FORMAT,
784 GST_TIME_ARGS (duration));
786 if (g_signal_handler_find (self, G_SIGNAL_MATCH_ID,
787 signals[SIGNAL_DURATION_CHANGED], 0, NULL, NULL, NULL) != 0) {
788 DurationChangedSignalData *data = g_new0 (DurationChangedSignalData, 1);
790 data->transcoder = g_object_ref (self);
791 data->duration = duration;
792 gst_transcoder_signal_dispatcher_dispatch (self->signal_dispatcher, self,
793 duration_changed_dispatch, data,
794 (GDestroyNotify) duration_changed_signal_data_free);
799 state_changed_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg,
802 GstTranscoder *self = GST_TRANSCODER (user_data);
803 GstState old_state, new_state, pending_state;
805 gst_message_parse_state_changed (msg, &old_state, &new_state, &pending_state);
807 if (GST_MESSAGE_SRC (msg) == GST_OBJECT (self->transcodebin)) {
808 gchar *transition_name;
810 GST_DEBUG_OBJECT (self, "Changed state old: %s new: %s pending: %s",
811 gst_element_state_get_name (old_state),
812 gst_element_state_get_name (new_state),
813 gst_element_state_get_name (pending_state));
815 transition_name = g_strdup_printf ("%s_%s",
816 gst_element_state_get_name (old_state),
817 gst_element_state_get_name (new_state));
818 dump_dot_file (self, transition_name);
819 g_free (transition_name);
821 self->current_state = new_state;
823 if (new_state == GST_STATE_PLAYING
824 && pending_state == GST_STATE_VOID_PENDING) {
825 add_tick_source (self);
831 duration_changed_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
834 GstTranscoder *self = GST_TRANSCODER (user_data);
837 if (gst_element_query_duration (self->transcodebin, GST_FORMAT_TIME,
839 emit_duration_changed (self, duration);
844 latency_cb (G_GNUC_UNUSED GstBus * bus, G_GNUC_UNUSED GstMessage * msg,
847 GstTranscoder *self = GST_TRANSCODER (user_data);
849 GST_DEBUG_OBJECT (self, "Latency changed");
851 gst_bin_recalculate_latency (GST_BIN (self->transcodebin));
855 request_state_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg,
858 GstTranscoder *self = GST_TRANSCODER (user_data);
860 GstStateChangeReturn state_ret;
862 gst_message_parse_request_state (msg, &state);
864 GST_DEBUG_OBJECT (self, "State %s requested",
865 gst_element_state_get_name (state));
867 self->target_state = state;
868 state_ret = gst_element_set_state (self->transcodebin, state);
869 if (state_ret == GST_STATE_CHANGE_FAILURE)
870 emit_error (self, g_error_new (GST_TRANSCODER_ERROR,
871 GST_TRANSCODER_ERROR_FAILED,
872 "Failed to change to requested state %s",
873 gst_element_state_get_name (state)), NULL);
877 element_cb (G_GNUC_UNUSED GstBus * bus, GstMessage * msg, gpointer user_data)
879 GstTranscoder *self = GST_TRANSCODER (user_data);
880 const GstStructure *s;
882 s = gst_message_get_structure (msg);
883 if (gst_structure_has_name (s, "redirect")) {
884 const gchar *new_location;
886 new_location = gst_structure_get_string (s, "new-location");
888 const GValue *locations_list, *location_val;
891 locations_list = gst_structure_get_value (s, "locations");
892 size = gst_value_list_get_size (locations_list);
893 for (i = 0; i < size; ++i) {
894 const GstStructure *location_s;
896 location_val = gst_value_list_get_value (locations_list, i);
897 if (!GST_VALUE_HOLDS_STRUCTURE (location_val))
900 location_s = (const GstStructure *) g_value_get_boxed (location_val);
901 if (!gst_structure_has_name (location_s, "redirect"))
904 new_location = gst_structure_get_string (location_s, "new-location");
911 GST_FIXME_OBJECT (self, "Handle redirection to '%s'", new_location);
918 gst_transcoder_main (gpointer data)
920 GstTranscoder *self = GST_TRANSCODER (data);
925 GST_TRACE_OBJECT (self, "Starting main thread");
927 g_main_context_push_thread_default (self->context);
929 source = g_idle_source_new ();
930 g_source_set_callback (source, (GSourceFunc) main_loop_running_cb, self,
932 g_source_attach (source, self->context);
933 g_source_unref (source);
935 self->bus = bus = gst_element_get_bus (self->transcodebin);
936 bus_source = gst_bus_create_watch (bus);
937 g_source_set_callback (bus_source, (GSourceFunc) gst_bus_async_signal_func,
939 g_source_attach (bus_source, self->context);
941 g_signal_connect (G_OBJECT (bus), "message::error", G_CALLBACK (error_cb),
943 g_signal_connect (G_OBJECT (bus), "message::warning", G_CALLBACK (warning_cb),
945 g_signal_connect (G_OBJECT (bus), "message::eos", G_CALLBACK (eos_cb), self);
946 g_signal_connect (G_OBJECT (bus), "message::state-changed",
947 G_CALLBACK (state_changed_cb), self);
948 g_signal_connect (G_OBJECT (bus), "message::clock-lost",
949 G_CALLBACK (clock_lost_cb), self);
950 g_signal_connect (G_OBJECT (bus), "message::duration-changed",
951 G_CALLBACK (duration_changed_cb), self);
952 g_signal_connect (G_OBJECT (bus), "message::latency",
953 G_CALLBACK (latency_cb), self);
954 g_signal_connect (G_OBJECT (bus), "message::request-state",
955 G_CALLBACK (request_state_cb), self);
956 g_signal_connect (G_OBJECT (bus), "message::element",
957 G_CALLBACK (element_cb), self);
959 self->target_state = GST_STATE_NULL;
960 self->current_state = GST_STATE_NULL;
961 self->is_eos = FALSE;
962 self->is_live = FALSE;
964 GST_TRACE_OBJECT (self, "Starting main loop");
965 g_main_loop_run (self->loop);
966 GST_TRACE_OBJECT (self, "Stopped main loop");
968 g_source_destroy (bus_source);
969 g_source_unref (bus_source);
970 gst_object_unref (bus);
972 remove_tick_source (self);
974 g_main_context_pop_thread_default (self->context);
976 self->target_state = GST_STATE_NULL;
977 self->current_state = GST_STATE_NULL;
978 if (self->transcodebin) {
979 gst_element_set_state (self->transcodebin, GST_STATE_NULL);
980 g_clear_object (&self->transcodebin);
983 GST_TRACE_OBJECT (self, "Stopped main thread");
989 gst_transcoder_init_once (G_GNUC_UNUSED gpointer user_data)
991 gst_init (NULL, NULL);
993 GST_DEBUG_CATEGORY_INIT (gst_transcoder_debug, "gst-transcoder", 0,
995 gst_transcoder_error_quark ();
1000 static GstEncodingProfile *
1001 create_encoding_profile (const gchar * pname)
1003 GstEncodingProfile *profile;
1004 GValue value = G_VALUE_INIT;
1006 g_value_init (&value, GST_TYPE_ENCODING_PROFILE);
1008 if (!gst_value_deserialize (&value, pname)) {
1009 g_value_reset (&value);
1014 profile = g_value_dup_object (&value);
1015 g_value_reset (&value);
1021 * gst_transcoder_new:
1022 * @source_uri: The URI of the media stream to transcode
1023 * @dest_uri: The URI of the destination of the transcoded stream
1024 * @encoding_profile: The serialized #GstEncodingProfile defining the output
1025 * format. Have a look at the #GstEncodingProfile documentation to find more
1026 * about the serialization format.
1028 * Returns: a new #GstTranscoder instance
1031 gst_transcoder_new (const gchar * source_uri,
1032 const gchar * dest_uri, const gchar * encoding_profile)
1034 GstEncodingProfile *profile;
1036 profile = create_encoding_profile (encoding_profile);
1038 return gst_transcoder_new_full (source_uri, dest_uri, profile, NULL);
1042 * gst_transcoder_new_full:
1043 * @source_uri: The URI of the media stream to transcode
1044 * @dest_uri: The URI of the destination of the transcoded stream
1045 * @profile: The #GstEncodingProfile defining the output format
1046 * have a look at the #GstEncodingProfile documentation to find more
1047 * about the serialization format.
1048 * @signal_dispatcher: The #GstTranscoderSignalDispatcher to be used
1049 * to dispatch the various signals.
1051 * Returns: a new #GstTranscoder instance
1054 gst_transcoder_new_full (const gchar * source_uri,
1055 const gchar * dest_uri, GstEncodingProfile * profile,
1056 GstTranscoderSignalDispatcher * signal_dispatcher)
1058 static GOnce once = G_ONCE_INIT;
1060 g_once (&once, gst_transcoder_init_once, NULL);
1062 g_return_val_if_fail (source_uri, NULL);
1063 g_return_val_if_fail (dest_uri, NULL);
1065 return g_object_new (GST_TYPE_TRANSCODER, "src-uri", source_uri,
1066 "dest-uri", dest_uri, "profile", profile,
1067 "signal-dispatcher", signal_dispatcher, NULL);
1077 _error_cb (GstTranscoder * self, GError * error, GstStructure * details,
1080 if (data->error == NULL)
1081 g_propagate_error (&data->error, error);
1084 g_main_loop_quit (data->loop);
1090 _done_cb (GstTranscoder * self, RunSyncData * data)
1093 g_main_loop_quit (data->loop);
1099 * gst_transcoder_run:
1100 * @self: The GstTranscoder to run
1101 * @error: (allow-none): An error to be set if transcoding fails
1103 * Run the transcoder task synchonously. You can connect
1104 * to the 'position' signal to get information about the
1105 * progress of the transcoding.
1108 gst_transcoder_run (GstTranscoder * self, GError ** error)
1110 RunSyncData data = { 0, };
1112 data.loop = g_main_loop_new (NULL, FALSE);
1113 g_signal_connect (self, "error", G_CALLBACK (_error_cb), &data);
1114 g_signal_connect (self, "done", G_CALLBACK (_done_cb), &data);
1115 gst_transcoder_run_async (self);
1118 g_main_loop_run (data.loop);
1120 g_signal_handlers_disconnect_by_func (self, _error_cb, &data);
1121 g_signal_handlers_disconnect_by_func (self, _done_cb, &data);
1125 g_propagate_error (error, data.error);
1127 g_clear_error (&data.error);
1135 * gst_transcoder_run_async:
1136 * @self: The GstTranscoder to run
1138 * Run the transcoder task asynchronously. You should connect
1139 * to the 'done' signal to be notified about when the
1140 * transcoding is done, and to the 'error' signal to be
1141 * notified about any error.
1144 gst_transcoder_run_async (GstTranscoder * self)
1146 GstStateChangeReturn state_ret;
1148 GST_DEBUG_OBJECT (self, "Play");
1150 if (!self->profile) {
1151 emit_error (self, g_error_new (GST_TRANSCODER_ERROR,
1152 GST_TRANSCODER_ERROR_FAILED, "No \"profile\" provided"), NULL);
1157 self->target_state = GST_STATE_PLAYING;
1158 state_ret = gst_element_set_state (self->transcodebin, GST_STATE_PLAYING);
1160 if (state_ret == GST_STATE_CHANGE_FAILURE) {
1161 emit_error (self, g_error_new (GST_TRANSCODER_ERROR,
1162 GST_TRANSCODER_ERROR_FAILED, "Could not start transcoding"), NULL);
1164 } else if (state_ret == GST_STATE_CHANGE_NO_PREROLL) {
1165 self->is_live = TRUE;
1166 GST_DEBUG_OBJECT (self, "Pipeline is live");
1173 gst_transcoder_set_position_update_interval_internal (gpointer user_data)
1175 GstTranscoder *self = user_data;
1177 GST_OBJECT_LOCK (self);
1179 if (self->tick_source) {
1180 remove_tick_source (self);
1181 add_tick_source (self);
1184 GST_OBJECT_UNLOCK (self);
1186 return G_SOURCE_REMOVE;
1190 * gst_transcoder_set_position_update_interval:
1191 * @self: #GstTranscoder instance
1192 * @interval: interval in ms
1194 * Set interval in milliseconds between two position-updated signals.
1195 * Pass 0 to stop updating the position.
1198 gst_transcoder_set_position_update_interval (GstTranscoder * self,
1201 g_return_if_fail (GST_IS_TRANSCODER (self));
1202 g_return_if_fail (interval <= 10000);
1204 GST_OBJECT_LOCK (self);
1205 self->position_update_interval_ms = interval;
1206 GST_OBJECT_UNLOCK (self);
1208 gst_transcoder_set_position_update_interval_internal (self);
1212 * gst_transcoder_get_position_update_interval:
1213 * @self: #GstTranscoder instance
1215 * Returns: current position update interval in milliseconds
1218 gst_transcoder_get_position_update_interval (GstTranscoder * self)
1220 g_return_val_if_fail (GST_IS_TRANSCODER (self),
1221 DEFAULT_POSITION_UPDATE_INTERVAL_MS);
1223 return self->position_update_interval_ms;
1227 * gst_transcoder_get_source_uri:
1228 * @self: #GstTranscoder instance
1230 * Gets the URI of the currently-transcoding stream.
1232 * Returns: (transfer full): a string containing the URI of the
1233 * source stream. g_free() after usage.
1236 gst_transcoder_get_source_uri (GstTranscoder * self)
1240 g_return_val_if_fail (GST_IS_TRANSCODER (self), DEFAULT_URI);
1242 g_object_get (self, "src-uri", &val, NULL);
1248 * gst_transcoder_get_dest_uri:
1249 * @self: #GstTranscoder instance
1251 * Gets the URI of the destination of the transcoded stream.
1253 * Returns: (transfer full): a string containing the URI of the
1254 * destination of the transcoded stream. g_free() after usage.
1257 gst_transcoder_get_dest_uri (GstTranscoder * self)
1261 g_return_val_if_fail (GST_IS_TRANSCODER (self), DEFAULT_URI);
1263 g_object_get (self, "dest-uri", &val, NULL);
1269 * gst_transcoder_get_position:
1270 * @self: #GstTranscoder instance
1272 * Returns: the absolute position time, in nanoseconds, of the
1273 * transcoding stream.
1276 gst_transcoder_get_position (GstTranscoder * self)
1280 g_return_val_if_fail (GST_IS_TRANSCODER (self), DEFAULT_POSITION);
1282 g_object_get (self, "position", &val, NULL);
1288 * gst_transcoder_get_duration:
1289 * @self: #GstTranscoder instance
1291 * Retrieves the duration of the media stream that self represents.
1293 * Returns: the duration of the transcoding media stream, in
1297 gst_transcoder_get_duration (GstTranscoder * self)
1301 g_return_val_if_fail (GST_IS_TRANSCODER (self), DEFAULT_DURATION);
1303 g_object_get (self, "duration", &val, NULL);
1309 * gst_transcoder_get_pipeline:
1310 * @self: #GstTranscoder instance
1312 * Returns: (transfer full): The internal uritranscodebin instance
1315 gst_transcoder_get_pipeline (GstTranscoder * self)
1319 g_return_val_if_fail (GST_IS_TRANSCODER (self), NULL);
1321 g_object_get (self, "pipeline", &val, NULL);
1327 * gst_transcoder_get_avoid_reencoding:
1328 * @self: The #GstTranscoder to check whether reencoding is avoided or not.
1330 * Returns: %TRUE if the transcoder tries to avoid reencoding streams where
1331 * reencoding is not strictly needed, %FALSE otherwise.
1334 gst_transcoder_get_avoid_reencoding (GstTranscoder * self)
1338 g_return_val_if_fail (GST_IS_TRANSCODER (self), FALSE);
1340 g_object_get (self->transcodebin, "avoid-reencoding", &val, NULL);
1346 * gst_transcoder_set_avoid_reencoding:
1347 * @self: The #GstTranscoder to set whether reencoding should be avoided or not.
1348 * @avoid_reencoding: %TRUE if the transcoder should try to avoid reencoding
1349 * streams where * reencoding is not strictly needed, %FALSE otherwise.
1352 gst_transcoder_set_avoid_reencoding (GstTranscoder * self,
1353 gboolean avoid_reencoding)
1355 g_return_if_fail (GST_IS_TRANSCODER (self));
1357 g_object_set (self->transcodebin, "avoid-reencoding", avoid_reencoding, NULL);
1360 #define C_ENUM(v) ((gint) v)
1361 #define C_FLAGS(v) ((guint) v)
1364 gst_transcoder_error_get_type (void)
1366 static gsize id = 0;
1367 static const GEnumValue values[] = {
1368 {C_ENUM (GST_TRANSCODER_ERROR_FAILED), "GST_TRANSCODER_ERROR_FAILED",
1373 if (g_once_init_enter (&id)) {
1374 GType tmp = g_enum_register_static ("GstTranscoderError", values);
1375 g_once_init_leave (&id, tmp);
1382 * gst_transcoder_error_get_name:
1383 * @error: a #GstTranscoderError
1385 * Gets a string representing the given error.
1387 * Returns: (transfer none): a string with the given error.
1390 gst_transcoder_error_get_name (GstTranscoderError error)
1393 case GST_TRANSCODER_ERROR_FAILED:
1397 g_assert_not_reached ();
1401 G_DEFINE_INTERFACE (GstTranscoderSignalDispatcher,
1402 gst_transcoder_signal_dispatcher, G_TYPE_OBJECT);
1405 gst_transcoder_signal_dispatcher_default_init (G_GNUC_UNUSED
1406 GstTranscoderSignalDispatcherInterface * iface)
1412 gst_transcoder_signal_dispatcher_dispatch (GstTranscoderSignalDispatcher * self,
1413 GstTranscoder * transcoder, void (*emitter) (gpointer data), gpointer data,
1414 GDestroyNotify destroy)
1416 GstTranscoderSignalDispatcherInterface *iface;
1425 g_return_if_fail (GST_IS_TRANSCODER_SIGNAL_DISPATCHER (self));
1426 iface = GST_TRANSCODER_SIGNAL_DISPATCHER_GET_INTERFACE (self);
1427 g_return_if_fail (iface->dispatch != NULL);
1429 iface->dispatch (self, transcoder, emitter, data, destroy);
1432 struct _GstTranscoderGMainContextSignalDispatcher
1435 GMainContext *application_context;
1438 struct _GstTranscoderGMainContextSignalDispatcherClass
1440 GObjectClass parent_class;
1444 gst_transcoder_g_main_context_signal_dispatcher_interface_init
1445 (GstTranscoderSignalDispatcherInterface * iface);
1449 G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_0,
1450 G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT,
1451 G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST
1454 G_DEFINE_TYPE_WITH_CODE (GstTranscoderGMainContextSignalDispatcher,
1455 gst_transcoder_g_main_context_signal_dispatcher, G_TYPE_OBJECT,
1456 G_IMPLEMENT_INTERFACE (GST_TYPE_TRANSCODER_SIGNAL_DISPATCHER,
1457 gst_transcoder_g_main_context_signal_dispatcher_interface_init));
1460 * g_main_context_signal_dispatcher_param_specs
1461 [G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST] = { NULL, };
1464 gst_transcoder_g_main_context_signal_dispatcher_finalize (GObject * object)
1466 GstTranscoderGMainContextSignalDispatcher *self =
1467 GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
1469 if (self->application_context)
1470 g_main_context_unref (self->application_context);
1473 (gst_transcoder_g_main_context_signal_dispatcher_parent_class)->finalize
1478 gst_transcoder_g_main_context_signal_dispatcher_set_property (GObject * object,
1479 guint prop_id, const GValue * value, GParamSpec * pspec)
1481 GstTranscoderGMainContextSignalDispatcher *self =
1482 GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
1485 case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
1486 self->application_context = g_value_dup_boxed (value);
1487 if (!self->application_context)
1488 self->application_context = g_main_context_ref_thread_default ();
1491 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1497 gst_transcoder_g_main_context_signal_dispatcher_get_property (GObject * object,
1498 guint prop_id, GValue * value, GParamSpec * pspec)
1500 GstTranscoderGMainContextSignalDispatcher *self =
1501 GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (object);
1504 case G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT:
1505 g_value_set_boxed (value, self->application_context);
1508 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1514 gst_transcoder_g_main_context_signal_dispatcher_class_init
1515 (GstTranscoderGMainContextSignalDispatcherClass * klass)
1517 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1519 gobject_class->finalize =
1520 gst_transcoder_g_main_context_signal_dispatcher_finalize;
1521 gobject_class->set_property =
1522 gst_transcoder_g_main_context_signal_dispatcher_set_property;
1523 gobject_class->get_property =
1524 gst_transcoder_g_main_context_signal_dispatcher_get_property;
1526 g_main_context_signal_dispatcher_param_specs
1527 [G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_APPLICATION_CONTEXT] =
1528 g_param_spec_boxed ("application-context", "Application Context",
1529 "Application GMainContext to dispatch signals to", G_TYPE_MAIN_CONTEXT,
1530 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS);
1532 g_object_class_install_properties (gobject_class,
1533 G_MAIN_CONTEXT_SIGNAL_DISPATCHER_PROP_LAST,
1534 g_main_context_signal_dispatcher_param_specs);
1538 gst_transcoder_g_main_context_signal_dispatcher_init
1539 (G_GNUC_UNUSED GstTranscoderGMainContextSignalDispatcher * self)
1545 void (*emitter) (gpointer data);
1547 GDestroyNotify destroy;
1548 } GMainContextSignalDispatcherData;
1551 g_main_context_signal_dispatcher_dispatch_gsourcefunc (gpointer user_data)
1553 GMainContextSignalDispatcherData *data = user_data;
1555 data->emitter (data->data);
1557 return G_SOURCE_REMOVE;
1561 g_main_context_signal_dispatcher_dispatch_destroy (gpointer user_data)
1563 GMainContextSignalDispatcherData *data = user_data;
1566 data->destroy (data->data);
1572 gst_transcoder_g_main_context_signal_dispatcher_dispatch (GstTranscoderSignalDispatcher * iface,
1573 G_GNUC_UNUSED GstTranscoder * transcoder, void (*emitter) (gpointer data),
1574 gpointer data, GDestroyNotify destroy)
1576 GstTranscoderGMainContextSignalDispatcher *self =
1577 GST_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER (iface);
1578 GMainContextSignalDispatcherData *gsourcefunc_data =
1579 g_new0 (GMainContextSignalDispatcherData, 1);
1581 gsourcefunc_data->emitter = emitter;
1582 gsourcefunc_data->data = data;
1583 gsourcefunc_data->destroy = destroy;
1585 g_main_context_invoke_full (self->application_context,
1586 G_PRIORITY_DEFAULT, g_main_context_signal_dispatcher_dispatch_gsourcefunc,
1587 gsourcefunc_data, g_main_context_signal_dispatcher_dispatch_destroy);
1591 gst_transcoder_g_main_context_signal_dispatcher_interface_init (GstTranscoderSignalDispatcherInterface * iface)
1593 iface->dispatch = gst_transcoder_g_main_context_signal_dispatcher_dispatch;
1598 * gst_transcoder_g_main_context_signal_dispatcher_new:
1599 * @application_context: (allow-none): GMainContext to use or %NULL
1601 * Returns: (transfer full):
1603 GstTranscoderSignalDispatcher *
1604 gst_transcoder_g_main_context_signal_dispatcher_new (GMainContext *
1605 application_context)
1607 return g_object_new (GST_TYPE_TRANSCODER_G_MAIN_CONTEXT_SIGNAL_DISPATCHER,
1608 "application-context", application_context, NULL);