• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  *
3  * Copyright (C) 2019-2020 Stephan Hesse <stephan@emliri.com>
4  * Copyright (C) 2020 Thibault Saunier <tsaunier@igalia.com>
5  *
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.
10  *
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.
15  *
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.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "gsttranscoder.h"
27 #include "gsttranscoder-signal-adapter.h"
28 
29 #include "gsttranscoder-private.h"
30 
31 #include <gst/gst.h>
32 
33 GST_DEBUG_CATEGORY_STATIC (gst_transcoder_signal_adapter_debug);
34 #define GST_CAT_DEFAULT gst_transcoder_signal_adapter_debug
35 
36 enum
37 {
38   SIGNAL_POSITION_UPDATED,
39   SIGNAL_DURATION_CHANGED,
40   SIGNAL_STATE_CHANGED,
41   SIGNAL_DONE,
42   SIGNAL_ERROR,
43   SIGNAL_WARNING,
44   SIGNAL_LAST
45 };
46 
47 enum
48 {
49   PROP_0,
50   PROP_TRANSCODER,
51   PROP_LAST
52 };
53 
54 static GParamSpec *param_specs[PROP_LAST] = { NULL, };
55 
56 struct _GstTranscoderSignalAdapterClass
57 {
58   GObjectClass parent_class;
59 };
60 
61 #define _do_init \
62   GST_DEBUG_CATEGORY_INIT (gst_transcoder_signal_adapter_debug, "gst-transcoder-signaladapter", \
63       0, "GstTranscoder signal adapter")
64 
65 #define parent_class gst_transcoder_signal_adapter_parent_class
66 G_DEFINE_TYPE_WITH_CODE (GstTranscoderSignalAdapter,
67     gst_transcoder_signal_adapter, G_TYPE_OBJECT, _do_init);
68 
69 static guint signals[SIGNAL_LAST] = { 0, };
70 
71 static void
gst_transcoder_signal_adapter_emit(GstTranscoderSignalAdapter * self,const GstStructure * message_data)72 gst_transcoder_signal_adapter_emit (GstTranscoderSignalAdapter * self,
73     const GstStructure * message_data)
74 {
75   GstTranscoderMessage transcoder_message_type;
76   g_return_if_fail (g_str_equal (gst_structure_get_name (message_data),
77           GST_TRANSCODER_MESSAGE_DATA));
78 
79   GST_LOG ("Emitting message %" GST_PTR_FORMAT, message_data);
80   gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_TYPE,
81       GST_TYPE_TRANSCODER_MESSAGE, &transcoder_message_type, NULL);
82 
83   switch (transcoder_message_type) {
84     case GST_TRANSCODER_MESSAGE_POSITION_UPDATED:{
85       GstClockTime pos = GST_CLOCK_TIME_NONE;
86       gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_POSITION,
87           GST_TYPE_CLOCK_TIME, &pos, NULL);
88       g_signal_emit (self, signals[SIGNAL_POSITION_UPDATED], 0, pos);
89       break;
90     }
91     case GST_TRANSCODER_MESSAGE_DURATION_CHANGED:{
92       GstClockTime duration = GST_CLOCK_TIME_NONE;
93       gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_DURATION,
94           GST_TYPE_CLOCK_TIME, &duration, NULL);
95       g_signal_emit (self, signals[SIGNAL_DURATION_CHANGED], 0, duration);
96       break;
97     }
98     case GST_TRANSCODER_MESSAGE_STATE_CHANGED:{
99       GstTranscoderState state;
100       gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_STATE,
101           GST_TYPE_TRANSCODER_STATE, &state, NULL);
102       g_signal_emit (self, signals[SIGNAL_STATE_CHANGED], 0, state);
103       break;
104     }
105     case GST_TRANSCODER_MESSAGE_DONE:
106       g_signal_emit (self, signals[SIGNAL_DONE], 0);
107       break;
108     case GST_TRANSCODER_MESSAGE_ERROR:{
109       GError *error = NULL;
110       GstStructure *details = NULL;
111 
112       gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_ERROR,
113           G_TYPE_ERROR, &error, GST_TYPE_STRUCTURE, &details, NULL);
114       g_signal_emit (self, signals[SIGNAL_ERROR], 0, error, details);
115       g_error_free (error);
116       if (details)
117         gst_structure_free (details);
118       break;
119     }
120     case GST_TRANSCODER_MESSAGE_WARNING:{
121       GstStructure *details = NULL;
122       GError *error = NULL;
123 
124       gst_structure_get (message_data, GST_TRANSCODER_MESSAGE_DATA_WARNING,
125           G_TYPE_ERROR, &error, GST_TYPE_STRUCTURE, &details, NULL);
126       g_signal_emit (self, signals[SIGNAL_WARNING], 0, error, details);
127       g_error_free (error);
128       if (details)
129         gst_structure_free (details);
130       break;
131     }
132     default:
133       g_assert_not_reached ();
134       break;
135   }
136 }
137 
138 /*
139  * callback for the bus-message in-sync handling
140  */
141 static GstBusSyncReply
gst_transcoder_signal_adapter_bus_sync_handler(GstBus * bus,GstMessage * message,gpointer user_data)142     gst_transcoder_signal_adapter_bus_sync_handler
143     (GstBus * bus, GstMessage * message, gpointer user_data)
144 {
145   GstTranscoderSignalAdapter *self = GST_TRANSCODER_SIGNAL_ADAPTER (user_data);
146   const GstStructure *message_data = gst_message_get_structure (message);
147   gst_transcoder_signal_adapter_emit (self, message_data);
148   gst_message_unref (message);
149   return GST_BUS_DROP;
150 }
151 
152 /*
153  * callback for the bus-watch
154  * pre: there is a message on the bus
155  */
156 static gboolean
gst_transcoder_signal_adapter_on_message(GstBus * bus,GstMessage * message,gpointer user_data)157 gst_transcoder_signal_adapter_on_message (GstBus * bus,
158     GstMessage * message, gpointer user_data)
159 {
160   GstTranscoderSignalAdapter *self = GST_TRANSCODER_SIGNAL_ADAPTER (user_data);
161   const GstStructure *message_data = gst_message_get_structure (message);
162   gst_transcoder_signal_adapter_emit (self, message_data);
163   return TRUE;
164 }
165 
166 /**
167  * gst_transcoder_signal_adapter_new:
168  * @transcoder: (transfer none): #GstTranscoder instance to emit signals for.
169  * @context: (nullable): A #GMainContext on which the main-loop will process
170  *                       transcoder bus messages on. Can be NULL (thread-default
171  *                       context will be used then).
172  *
173  * A bus-watching #GSource will be created and attached to the context. The
174  * attached callback will emit the corresponding signal for the message
175  * received. Matching signals for transcoder messages from the bus will be
176  * emitted by it on the created adapter object.
177  *
178  * Returns: (transfer full)(nullable): A new #GstTranscoderSignalAdapter to
179  * connect signal handlers to.
180  *
181  * Since: 1.20
182  */
183 GstTranscoderSignalAdapter *
gst_transcoder_signal_adapter_new(GstTranscoder * transcoder,GMainContext * context)184 gst_transcoder_signal_adapter_new (GstTranscoder * transcoder,
185     GMainContext * context)
186 {
187   GstTranscoderSignalAdapter *self = NULL;
188 
189   g_return_val_if_fail (GST_IS_TRANSCODER (transcoder), NULL);
190 
191   self = g_object_new (GST_TYPE_TRANSCODER_SIGNAL_ADAPTER, NULL);
192   self->bus = gst_transcoder_get_message_bus (transcoder);
193   self->source = gst_bus_create_watch (self->bus);
194 
195   if (!self->source) {
196     GST_ERROR_OBJECT (transcoder, "Could not create watch.");
197 
198     gst_object_unref (self);
199 
200     return NULL;
201   }
202 
203   g_weak_ref_set (&self->transcoder, transcoder);
204   g_source_attach (self->source, context);
205   g_source_set_callback (self->source,
206       (GSourceFunc) gst_transcoder_signal_adapter_on_message, self, NULL);
207   return self;
208 }
209 
210 /**
211  * gst_transcoder_signal_adapter_new_sync_emit:
212  * @transcoder: (transfer none): #GstTranscoder instance to emit signals
213  * synchronously for.
214  *
215  * Returns: (transfer full): A new #GstTranscoderSignalAdapter to connect signal
216  * handlers to.
217  *
218  * Since: 1.20
219  */
220 GstTranscoderSignalAdapter *
gst_transcoder_signal_adapter_new_sync_emit(GstTranscoder * transcoder)221 gst_transcoder_signal_adapter_new_sync_emit (GstTranscoder * transcoder)
222 {
223   GstBus *bus = NULL;
224   GstTranscoderSignalAdapter *self = NULL;
225 
226   g_return_val_if_fail (GST_IS_TRANSCODER (transcoder), NULL);
227 
228   bus = gst_transcoder_get_message_bus (transcoder);
229 
230   self = g_object_new (GST_TYPE_TRANSCODER_SIGNAL_ADAPTER, NULL);
231   self->bus = bus;
232   gst_bus_set_sync_handler (self->bus,
233       gst_transcoder_signal_adapter_bus_sync_handler, self, NULL);
234   return self;
235 }
236 
237 static void
gst_transcoder_signal_adapter_init(GstTranscoderSignalAdapter * self)238 gst_transcoder_signal_adapter_init (GstTranscoderSignalAdapter * self)
239 {
240   self->source = NULL;
241 }
242 
243 static void
gst_transcoder_signal_adapter_dispose(GObject * object)244 gst_transcoder_signal_adapter_dispose (GObject * object)
245 {
246   GstTranscoderSignalAdapter *self = GST_TRANSCODER_SIGNAL_ADAPTER (object);
247 
248   if (self->source) {
249     g_source_destroy (self->source);
250     g_source_unref (self->source);
251     self->source = NULL;
252   }
253 
254   gst_clear_object (&self->bus);
255 
256   G_OBJECT_CLASS (parent_class)->dispose (object);
257 }
258 
259 static void
gst_transcoder_signal_adapter_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)260 gst_transcoder_signal_adapter_get_property (GObject * object, guint prop_id,
261     GValue * value, GParamSpec * pspec)
262 {
263   GstTranscoderSignalAdapter *self = GST_TRANSCODER_SIGNAL_ADAPTER (object);
264 
265   switch (prop_id) {
266     case PROP_TRANSCODER:
267       g_value_take_object (value, g_weak_ref_get (&self->transcoder));
268       break;
269     default:
270       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
271       break;
272   }
273 }
274 
275 static void
gst_transcoder_signal_adapter_class_init(GstTranscoderSignalAdapterClass * klass)276 gst_transcoder_signal_adapter_class_init (GstTranscoderSignalAdapterClass *
277     klass)
278 {
279   GObjectClass *gobject_class = (GObjectClass *) klass;
280 
281   gobject_class->dispose = gst_transcoder_signal_adapter_dispose;
282   gobject_class->get_property = gst_transcoder_signal_adapter_get_property;
283 
284   signals[SIGNAL_POSITION_UPDATED] =
285       g_signal_new ("position-updated", G_TYPE_FROM_CLASS (klass),
286       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
287       NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
288 
289   signals[SIGNAL_DURATION_CHANGED] =
290       g_signal_new ("duration-changed", G_TYPE_FROM_CLASS (klass),
291       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
292       NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_CLOCK_TIME);
293 
294   signals[SIGNAL_DONE] =
295       g_signal_new ("done", G_TYPE_FROM_CLASS (klass),
296       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
297       NULL, NULL, G_TYPE_NONE, 0, G_TYPE_INVALID);
298 
299   signals[SIGNAL_ERROR] =
300       g_signal_new ("error", G_TYPE_FROM_CLASS (klass),
301       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
302       NULL, NULL, G_TYPE_NONE, 2, G_TYPE_ERROR, GST_TYPE_STRUCTURE);
303 
304   signals[SIGNAL_WARNING] =
305       g_signal_new ("warning", G_TYPE_FROM_CLASS (klass),
306       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
307       NULL, NULL, G_TYPE_NONE, 2, G_TYPE_ERROR, GST_TYPE_STRUCTURE);
308 
309   signals[SIGNAL_STATE_CHANGED] =
310       g_signal_new ("state-changed", G_TYPE_FROM_CLASS (klass),
311       G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, 0, NULL,
312       NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_TRANSCODER_STATE);
313 
314   /**
315    * GstTranscoderSignalAdapter:transcoder:
316    *
317    * The #GstTranscoder tracked by the adapter.
318    *
319    * Since: 1.20
320    */
321   param_specs[PROP_TRANSCODER] =
322       g_param_spec_object ("transcoder", "Transcoder",
323       "The GstTranscoder @self is tracking", GST_TYPE_TRANSCODER,
324       G_PARAM_READABLE);
325 
326   g_object_class_install_properties (gobject_class, PROP_LAST, param_specs);
327 }
328 
329 
330 /**
331  * gst_transcoder_signal_adapter_get_transcoder:
332  * @self: The #GstTranscoderSignalAdapter
333  *
334  * Returns: (transfer full)(nullable): The #GstTranscoder @self is tracking
335  *
336  * Since: 1.20
337  */
338 GstTranscoder *
gst_transcoder_signal_adapter_get_transcoder(GstTranscoderSignalAdapter * self)339 gst_transcoder_signal_adapter_get_transcoder (GstTranscoderSignalAdapter * self)
340 {
341   return g_weak_ref_get (&self->transcoder);
342 }
343