• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) 2019 Thibault Saunier <tsaunier@igalia.com>
3  *
4  * gsturitranscodebin.c:
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 #ifdef HAVE_CONFIG_H
22 #  include "config.h"
23 #endif
24 
25 #include "gsttranscoding.h"
26 #include "gsttranscodeelements.h"
27 #if HAVE_GETRUSAGE
28 #include "gst-cpu-throttling-clock.h"
29 #endif
30 #include <gst/pbutils/pbutils.h>
31 
32 #include <gst/pbutils/missing-plugins.h>
33 
34 GST_DEBUG_CATEGORY_STATIC (gst_uri_transcodebin_debug);
35 #define GST_CAT_DEFAULT gst_uri_transcodebin_debug
36 
37 typedef struct
38 {
39   GstPipeline parent;
40 
41   GstElement *src;
42   gchar *source_uri;
43 
44   GstElement *transcodebin;
45 
46   GstElement *audio_filter;
47   GstElement *video_filter;
48 
49   GstEncodingProfile *profile;
50   gboolean avoid_reencoding;
51   guint wanted_cpu_usage;
52 
53   GstElement *sink;
54   gchar *dest_uri;
55 
56   GstClock *cpu_clock;
57 
58 } GstUriTranscodeBin;
59 
60 typedef struct
61 {
62   GstPipelineClass parent;
63 
64 } GstUriTranscodeBinClass;
65 
66 /* *INDENT-OFF* */
67 #define parent_class gst_uri_transcode_bin_parent_class
68 #define GST_TYPE_URI_TRANSCODE_BIN (gst_uri_transcode_bin_get_type ())
69 #define GST_URI_TRANSCODE_BIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_URI_TRANSCODE_BIN, GstUriTranscodeBin))
70 #define GST_URI_TRANSCODE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_URI_TRANSCODE_BIN_TYPE, GstUriTranscodeBinClass))
71 #define GST_IS_TRANSCODE_BIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_URI_TRANSCODE_BIN_TYPE))
72 #define GST_IS_TRANSCODE_BIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_URI_TRANSCODE_BIN_TYPE))
73 #define GST_URI_TRANSCODE_BIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_URI_TRANSCODE_BIN_TYPE, GstUriTranscodeBinClass))
74 
75 #define DEFAULT_AVOID_REENCODING   FALSE
76 
77 G_DEFINE_TYPE (GstUriTranscodeBin, gst_uri_transcode_bin, GST_TYPE_PIPELINE);
78 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (uritranscodebin, "uritranscodebin", GST_RANK_NONE,
79     gst_uri_transcode_bin_get_type (), transcodebin_element_init (plugin));
80 
81 enum
82 {
83  PROP_0,
84  PROP_PROFILE,
85  PROP_SOURCE_URI,
86  PROP_DEST_URI,
87  PROP_AVOID_REENCODING,
88  PROP_SINK,
89  PROP_SRC,
90  PROP_CPU_USAGE,
91  PROP_VIDEO_FILTER,
92  PROP_AUDIO_FILTER,
93  LAST_PROP
94 };
95 
96 /* signals */
97 enum
98 {
99   SIGNAL_SOURCE_SETUP,
100   SIGNAL_ELEMENT_SETUP,
101   LAST_SIGNAL
102 };
103 static guint signals[LAST_SIGNAL] = { 0 };
104 
105 static void
post_missing_plugin_error(GstElement * dec,const gchar * element_name)106 post_missing_plugin_error (GstElement * dec, const gchar * element_name)
107 {
108   GstMessage *msg;
109 
110   msg = gst_missing_element_message_new (dec, element_name);
111   gst_element_post_message (dec, msg);
112 
113   GST_ELEMENT_ERROR (dec, CORE, MISSING_PLUGIN,
114       ("Missing element '%s' - check your GStreamer installation.",
115           element_name), (NULL));
116 }
117 /* *INDENT-ON* */
118 
119 static gboolean
make_dest(GstUriTranscodeBin * self)120 make_dest (GstUriTranscodeBin * self)
121 {
122   GError *err = NULL;
123 
124   GST_OBJECT_LOCK (self);
125   if (!self->dest_uri) {
126     GST_INFO_OBJECT (self, "Sink already set: %" GST_PTR_FORMAT, self->sink);
127     goto ok_unlock;
128   }
129 
130   if (!self->dest_uri)
131     goto ok_unlock;
132 
133   if (!gst_uri_is_valid (self->dest_uri))
134     goto invalid_uri_unlock;
135 
136   self->sink = gst_element_make_from_uri (GST_URI_SINK, self->dest_uri,
137       "sink", &err);
138   if (!self->sink)
139     goto no_sink_unlock;
140 
141   GST_OBJECT_UNLOCK (self);
142   gst_bin_add (GST_BIN (self), self->sink);
143   g_object_set (self->sink, "sync", TRUE, "max-lateness", GST_CLOCK_TIME_NONE,
144       NULL);
145 
146   return TRUE;
147 
148 ok_unlock:
149   GST_OBJECT_UNLOCK (self);
150   return TRUE;
151 
152 invalid_uri_unlock:
153   {
154     GST_OBJECT_UNLOCK (self);
155     GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
156         ("Invalid URI \"%s\".", self->dest_uri), (NULL));
157     g_clear_error (&err);
158     return FALSE;
159   }
160 
161 invalid_uri:
162   {
163     GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
164         ("Invalid URI \"%s\".", self->source_uri), (NULL));
165     g_clear_error (&err);
166     return FALSE;
167   }
168 
169 no_sink_unlock:
170   {
171     GST_OBJECT_UNLOCK (self);
172     /* whoops, could not create the source element, dig a little deeper to
173      * figure out what might be wrong. */
174     if (err != NULL && err->code == GST_URI_ERROR_UNSUPPORTED_PROTOCOL) {
175       gchar *prot;
176 
177       prot = gst_uri_get_protocol (self->dest_uri);
178       if (prot == NULL)
179         goto invalid_uri;
180 
181       gst_element_post_message (GST_ELEMENT_CAST (self),
182           gst_missing_uri_source_message_new (GST_ELEMENT (self), prot));
183 
184       GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN,
185           ("No URI handler implemented for \"%s\".", prot), (NULL));
186 
187       g_free (prot);
188     } else {
189       GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
190           ("%s", (err) ? err->message : "URI was not accepted by any element"),
191           ("No element accepted URI '%s'", self->dest_uri));
192     }
193 
194     g_clear_error (&err);
195 
196     return FALSE;
197   }
198 }
199 
200 static void
transcodebin_pad_added_cb(GstElement * transcodebin,GstPad * pad,GstUriTranscodeBin * self)201 transcodebin_pad_added_cb (GstElement * transcodebin, GstPad * pad,
202     GstUriTranscodeBin * self)
203 {
204 
205   GstPad *sinkpad;
206 
207   if (GST_PAD_IS_SINK (pad))
208     return;
209 
210   make_dest (self);
211   if (!self->sink) {
212     GST_ELEMENT_ERROR (self, CORE, FAILED, (NULL), ("No sink configured."));
213     return;
214   }
215 
216   sinkpad = gst_element_get_static_pad (self->sink, "sink");
217   if (!sinkpad) {
218     GST_ELEMENT_ERROR (self, CORE, FAILED, (NULL), ("Sink has not sinkpad?!"));
219     return;
220   }
221 
222   if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK) {
223     GST_ERROR_OBJECT (self,
224         "Could not link %" GST_PTR_FORMAT " and %" GST_PTR_FORMAT, pad,
225         sinkpad);
226     /* Let `pad unlinked` error pop up later */
227   }
228 }
229 
230 static gboolean
make_transcodebin(GstUriTranscodeBin * self)231 make_transcodebin (GstUriTranscodeBin * self)
232 {
233   GST_INFO_OBJECT (self, "making new transcodebin");
234 
235   self->transcodebin = gst_element_factory_make ("transcodebin", NULL);
236   if (!self->transcodebin)
237     goto no_transcodebin;
238 
239   g_signal_connect (self->transcodebin, "pad-added",
240       G_CALLBACK (transcodebin_pad_added_cb), self);
241 
242   g_object_set (self->transcodebin, "profile", self->profile,
243       "video-filter", self->video_filter,
244       "audio-filter", self->audio_filter,
245       "avoid-reencoding", self->avoid_reencoding, NULL);
246 
247   gst_bin_add (GST_BIN (self), self->transcodebin);
248 
249   return TRUE;
250 
251   /* ERRORS */
252 no_transcodebin:
253   {
254     post_missing_plugin_error (GST_ELEMENT_CAST (self), "transcodebin");
255 
256     GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
257         ("No transcodebin element, check your installation"));
258 
259     return FALSE;
260   }
261 }
262 
263 static void
src_pad_added_cb(GstElement * src,GstPad * pad,GstUriTranscodeBin * self)264 src_pad_added_cb (GstElement * src, GstPad * pad, GstUriTranscodeBin * self)
265 {
266   GstPad *sinkpad = NULL;
267   GstPadLinkReturn res;
268 
269   GST_DEBUG_OBJECT (self,
270       "New pad %" GST_PTR_FORMAT " from source %" GST_PTR_FORMAT, pad, src);
271 
272   sinkpad = gst_element_get_static_pad (self->transcodebin, "sink");
273 
274   if (gst_pad_is_linked (sinkpad))
275     sinkpad = gst_element_request_pad_simple (self->transcodebin, "sink_%u");
276 
277   if (sinkpad) {
278     GST_DEBUG_OBJECT (self,
279         "Linking %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT, pad, sinkpad);
280     res = gst_pad_link (pad, sinkpad);
281     gst_object_unref (sinkpad);
282     if (GST_PAD_LINK_FAILED (res))
283       goto link_failed;
284   }
285   return;
286 
287 link_failed:
288   {
289     GST_ERROR_OBJECT (self,
290         "failed to link pad %s:%s to decodebin, reason %s (%d)",
291         GST_DEBUG_PAD_NAME (pad), gst_pad_link_get_name (res), res);
292     return;
293   }
294 }
295 
296 static void
src_pad_removed_cb(GstElement * element,GstPad * pad,GstUriTranscodeBin * self)297 src_pad_removed_cb (GstElement * element, GstPad * pad,
298     GstUriTranscodeBin * self)
299 {
300   /* FIXME : IMPLEMENT */
301 }
302 
303 static void
source_setup_cb(GstElement * element,GstElement * source,GstUriTranscodeBin * self)304 source_setup_cb (GstElement * element, GstElement * source,
305     GstUriTranscodeBin * self)
306 {
307   g_signal_emit (self, signals[SIGNAL_SOURCE_SETUP], 0, source);
308 }
309 
310 static gboolean
make_source(GstUriTranscodeBin * self)311 make_source (GstUriTranscodeBin * self)
312 {
313   GError *err = NULL;
314 
315   if (!gst_uri_is_valid (self->source_uri))
316     goto invalid_uri;
317 
318   self->src = gst_element_factory_make ("urisourcebin", NULL);
319   if (!self->src)
320     goto no_urisourcebin;
321 
322   gst_bin_add (GST_BIN (self), self->src);
323 
324   g_object_set (self->src, "uri", self->source_uri, NULL);
325 
326   g_signal_connect (self->src, "pad-added", (GCallback) src_pad_added_cb, self);
327   g_signal_connect (self->src, "pad-removed",
328       (GCallback) src_pad_removed_cb, self);
329   g_signal_connect (self->src, "source-setup",
330       G_CALLBACK (source_setup_cb), self);
331 
332   return TRUE;
333 
334 invalid_uri:
335   {
336     GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND,
337         ("Invalid URI \"%s\".", self->source_uri), (NULL));
338     g_clear_error (&err);
339     return FALSE;
340   }
341 
342 no_urisourcebin:
343   {
344     post_missing_plugin_error (GST_ELEMENT_CAST (self), "urisourcebin");
345 
346     GST_ELEMENT_ERROR (self, CORE, MISSING_PLUGIN, (NULL),
347         ("No urisourcebin element, check your installation"));
348 
349     return FALSE;
350   }
351 
352 }
353 
354 static void
remove_all_children(GstUriTranscodeBin * self)355 remove_all_children (GstUriTranscodeBin * self)
356 {
357   if (self->sink) {
358     gst_element_set_state (self->sink, GST_STATE_NULL);
359     gst_bin_remove (GST_BIN (self), self->sink);
360     self->sink = NULL;
361   }
362 
363   if (self->transcodebin) {
364     gst_element_set_state (self->transcodebin, GST_STATE_NULL);
365     gst_bin_remove (GST_BIN (self), self->transcodebin);
366     self->transcodebin = NULL;
367   }
368 
369   if (self->src) {
370     gst_element_set_state (self->src, GST_STATE_NULL);
371     gst_bin_remove (GST_BIN (self), self->src);
372     self->src = NULL;
373   }
374 }
375 
376 static void
set_location_on_muxer_if_sink(GstUriTranscodeBin * self,GstElement * child)377 set_location_on_muxer_if_sink (GstUriTranscodeBin * self, GstElement * child)
378 {
379   GstElementFactory *factory = gst_element_get_factory (child);
380 
381   if (!factory)
382     return;
383 
384   if (!self->dest_uri)
385     return;
386 
387   /* Set out dest URI as location for muxer sinks. */
388   if (!gst_element_factory_list_is_type (factory,
389           GST_ELEMENT_FACTORY_TYPE_MUXER) ||
390       !gst_element_factory_list_is_type (factory,
391           GST_ELEMENT_FACTORY_TYPE_SINK)) {
392 
393     return;
394   }
395 
396   if (!g_object_class_find_property (G_OBJECT_GET_CLASS (child), "location"))
397     return;
398 
399   if (!gst_uri_has_protocol (self->dest_uri, "file")) {
400     GST_ELEMENT_ERROR (self, RESOURCE, SETTINGS,
401         ("Trying to use a not local file with a muxing sink which is not"
402             " supported."), (NULL));
403     return;
404   }
405 
406   GST_OBJECT_FLAG_SET (self->transcodebin, GST_ELEMENT_FLAG_SINK);
407   g_object_set (child, "location", &self->dest_uri[strlen ("file://")], NULL);
408   GST_DEBUG_OBJECT (self, "Setting location: %s",
409       &self->dest_uri[strlen ("file://")]);
410 }
411 
412 static void
deep_element_added(GstBin * bin,GstBin * sub_bin,GstElement * child)413 deep_element_added (GstBin * bin, GstBin * sub_bin, GstElement * child)
414 {
415   GstUriTranscodeBin *self = GST_URI_TRANSCODE_BIN (bin);
416 
417   set_location_on_muxer_if_sink (self, child);
418   g_signal_emit (bin, signals[SIGNAL_ELEMENT_SETUP], 0, child);
419 
420   GST_BIN_CLASS (parent_class)->deep_element_added (bin, sub_bin, child);
421 }
422 
423 static GstStateChangeReturn
gst_uri_transcode_bin_change_state(GstElement * element,GstStateChange transition)424 gst_uri_transcode_bin_change_state (GstElement * element,
425     GstStateChange transition)
426 {
427   GstStateChangeReturn ret;
428   GstUriTranscodeBin *self = GST_URI_TRANSCODE_BIN (element);
429 
430   switch (transition) {
431     case GST_STATE_CHANGE_READY_TO_PAUSED:
432 
433       if (!make_transcodebin (self))
434         goto setup_failed;
435 
436       if (!make_source (self))
437         goto setup_failed;
438 
439       if (self->sink && gst_element_set_state (self->sink,
440               GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
441         GST_ERROR_OBJECT (self,
442             "Could not set %" GST_PTR_FORMAT " state to PAUSED", self->sink);
443         goto setup_failed;
444       }
445 
446       if (gst_element_set_state (self->transcodebin,
447               GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
448         GST_ERROR_OBJECT (self,
449             "Could not set %" GST_PTR_FORMAT " state to PAUSED",
450             self->transcodebin);
451         goto setup_failed;
452       }
453 
454       if (gst_element_set_state (self->src,
455               GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) {
456         GST_ERROR_OBJECT (self,
457             "Could not set %" GST_PTR_FORMAT " state to PAUSED", self->src);
458         goto setup_failed;
459       }
460 
461       break;
462     default:
463       break;
464   }
465 
466   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
467 
468   if (ret == GST_STATE_CHANGE_FAILURE)
469     goto beach;
470 
471   switch (transition) {
472     case GST_STATE_CHANGE_PAUSED_TO_READY:
473       remove_all_children (self);
474       break;
475     default:
476       break;
477   }
478 
479 beach:
480   return ret;
481 
482 setup_failed:
483   remove_all_children (self);
484   return GST_STATE_CHANGE_FAILURE;
485 }
486 
487 static void
gst_uri_transcode_bin_constructed(GObject * object)488 gst_uri_transcode_bin_constructed (GObject * object)
489 {
490 #if HAVE_GETRUSAGE
491   GstUriTranscodeBin *self = GST_URI_TRANSCODE_BIN (object);
492 
493   self->cpu_clock =
494       GST_CLOCK (gst_cpu_throttling_clock_new (self->wanted_cpu_usage));
495   gst_pipeline_use_clock (GST_PIPELINE (self), self->cpu_clock);
496 #endif
497 
498   ((GObjectClass *) parent_class)->constructed (object);
499 }
500 
501 static void
gst_uri_transcode_bin_dispose(GObject * object)502 gst_uri_transcode_bin_dispose (GObject * object)
503 {
504   GstUriTranscodeBin *self = (GstUriTranscodeBin *) object;
505 
506   g_clear_object (&self->video_filter);
507   g_clear_object (&self->audio_filter);
508   g_clear_object (&self->cpu_clock);
509 
510   G_OBJECT_CLASS (gst_uri_transcode_bin_parent_class)->dispose (object);
511 }
512 
513 static void
gst_uri_transcode_bin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)514 gst_uri_transcode_bin_get_property (GObject * object,
515     guint prop_id, GValue * value, GParamSpec * pspec)
516 {
517   GstUriTranscodeBin *self = GST_URI_TRANSCODE_BIN (object);
518 
519   switch (prop_id) {
520     case PROP_PROFILE:
521       GST_OBJECT_LOCK (self);
522       g_value_set_object (value, self->profile);
523       GST_OBJECT_UNLOCK (self);
524       break;
525     case PROP_DEST_URI:
526       GST_OBJECT_LOCK (self);
527       g_value_set_string (value, self->dest_uri);
528       GST_OBJECT_UNLOCK (self);
529       break;
530     case PROP_SOURCE_URI:
531       GST_OBJECT_LOCK (self);
532       g_value_set_string (value, self->source_uri);
533       GST_OBJECT_UNLOCK (self);
534       break;
535     case PROP_AVOID_REENCODING:
536       GST_OBJECT_LOCK (self);
537       g_value_set_boolean (value, self->avoid_reencoding);
538       GST_OBJECT_UNLOCK (self);
539       break;
540     case PROP_CPU_USAGE:
541       GST_OBJECT_LOCK (self);
542       g_value_set_uint (value, self->wanted_cpu_usage);
543       GST_OBJECT_UNLOCK (self);
544       break;
545     case PROP_VIDEO_FILTER:
546       GST_OBJECT_LOCK (self);
547       g_value_set_object (value, self->video_filter);
548       GST_OBJECT_UNLOCK (self);
549       break;
550     case PROP_AUDIO_FILTER:
551       GST_OBJECT_LOCK (self);
552       g_value_set_object (value, self->audio_filter);
553       GST_OBJECT_UNLOCK (self);
554       break;
555     default:
556       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
557   }
558 }
559 
560 static void
gst_uri_transcode_bin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)561 gst_uri_transcode_bin_set_property (GObject * object,
562     guint prop_id, const GValue * value, GParamSpec * pspec)
563 {
564   GstUriTranscodeBin *self = GST_URI_TRANSCODE_BIN (object);
565 
566   switch (prop_id) {
567     case PROP_PROFILE:
568       GST_OBJECT_LOCK (self);
569       self->profile = g_value_dup_object (value);
570       GST_OBJECT_UNLOCK (self);
571       break;
572     case PROP_DEST_URI:
573       GST_OBJECT_LOCK (self);
574       g_free (self->dest_uri);
575       self->dest_uri = g_value_dup_string (value);
576       GST_OBJECT_UNLOCK (self);
577       break;
578     case PROP_SOURCE_URI:
579       GST_OBJECT_LOCK (self);
580       g_free (self->source_uri);
581       self->source_uri = g_value_dup_string (value);
582       GST_OBJECT_UNLOCK (self);
583       break;
584     case PROP_AVOID_REENCODING:
585       GST_OBJECT_LOCK (self);
586       self->avoid_reencoding = g_value_get_boolean (value);
587       GST_OBJECT_UNLOCK (self);
588       break;
589     case PROP_CPU_USAGE:
590 #if HAVE_GETRUSAGE
591       GST_OBJECT_LOCK (self);
592       self->wanted_cpu_usage = g_value_get_uint (value);
593       g_object_set (self->cpu_clock, "cpu-usage", self->wanted_cpu_usage, NULL);
594       GST_OBJECT_UNLOCK (self);
595 #else
596       GST_ERROR_OBJECT (self,
597           "No CPU usage throttling support for that platform");
598 #endif
599       break;
600     case PROP_AUDIO_FILTER:
601       GST_OBJECT_LOCK (self);
602       self->audio_filter = g_value_dup_object (value);
603       GST_OBJECT_UNLOCK (self);
604       break;
605     case PROP_VIDEO_FILTER:
606       GST_OBJECT_LOCK (self);
607       self->video_filter = g_value_dup_object (value);
608       GST_OBJECT_UNLOCK (self);
609       break;
610     default:
611       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
612   }
613 }
614 
615 static void
gst_uri_transcode_bin_class_init(GstUriTranscodeBinClass * klass)616 gst_uri_transcode_bin_class_init (GstUriTranscodeBinClass * klass)
617 {
618   GObjectClass *object_class = G_OBJECT_CLASS (klass);
619   GstElementClass *gstelement_klass;
620   GstBinClass *gstbin_klass;
621 
622   object_class->get_property = gst_uri_transcode_bin_get_property;
623   object_class->set_property = gst_uri_transcode_bin_set_property;
624   object_class->constructed = gst_uri_transcode_bin_constructed;
625   object_class->dispose = gst_uri_transcode_bin_dispose;
626 
627   gstelement_klass = (GstElementClass *) klass;
628   gstelement_klass->change_state =
629       GST_DEBUG_FUNCPTR (gst_uri_transcode_bin_change_state);
630 
631   gstbin_klass = (GstBinClass *) klass;
632   gstbin_klass->deep_element_added = GST_DEBUG_FUNCPTR (deep_element_added);
633 
634   GST_DEBUG_CATEGORY_INIT (gst_uri_transcodebin_debug, "uritranscodebin", 0,
635       "UriTranscodebin element");
636 
637   gst_element_class_set_static_metadata (gstelement_klass,
638       "URITranscode Bin", "Generic/Bin/Encoding",
639       "Autoplug and transcoder media from uris",
640       "Thibault Saunier <tsaunier@igalia.com>");
641 
642   /**
643    * GstUriTranscodeBin:profile:
644    *
645    * The #GstEncodingProfile to use. This property must be set before going
646    * to %GST_STATE_PAUSED or higher.
647    */
648   g_object_class_install_property (object_class, PROP_PROFILE,
649       g_param_spec_object ("profile", "Profile",
650           "The GstEncodingProfile to use", GST_TYPE_ENCODING_PROFILE,
651           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
652 
653   /**
654    * GstUriTranscodeBin:source-uri:
655    *
656    * The URI of the stream to encode
657    */
658   g_object_class_install_property (object_class, PROP_SOURCE_URI,
659       g_param_spec_string ("source-uri", "Source URI", "URI to decode",
660           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
661 
662   /**
663    * GstUriTranscodeBin:dest-uri:
664    *
665    * The destination URI to which the stream should be encoded.
666    */
667   g_object_class_install_property (object_class, PROP_DEST_URI,
668       g_param_spec_string ("dest-uri", "URI", "URI to put output stream",
669           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
670 
671   /**
672    * GstUriTranscodeBin:avoid-reencoding:
673    *
674    * See #encodebin:avoid-reencoding
675    */
676   g_object_class_install_property (object_class, PROP_AVOID_REENCODING,
677       g_param_spec_boolean ("avoid-reencoding", "Avoid re-encoding",
678           "Whether to re-encode portions of compatible video streams that lay on segment boundaries",
679           DEFAULT_AVOID_REENCODING,
680           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
681 
682   g_object_class_install_property (object_class, PROP_CPU_USAGE,
683       g_param_spec_uint ("cpu-usage", "cpu-usage",
684           "The percentage of CPU to try to use with the processus running the "
685           "pipeline driven by the clock", 0, 100,
686           100, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
687 
688   /**
689    * GstUriTranscodeBin:video-filter:
690    *
691    * Set the video filter element/bin to use.
692    */
693   g_object_class_install_property (object_class, PROP_VIDEO_FILTER,
694       g_param_spec_object ("video-filter", "Video filter",
695           "the video filter(s) to apply, if possible",
696           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
697   /**
698    * GstUriTranscodeBin:audio-filter:
699    *
700    * Set the audio filter element/bin to use.
701    */
702   g_object_class_install_property (object_class, PROP_AUDIO_FILTER,
703       g_param_spec_object ("audio-filter", "Audio filter",
704           "the audio filter(s) to apply, if possible",
705           GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
706 
707   /**
708    * GstUriTranscodeBin::source-setup:
709    * @uritranscodebin: a #GstUriTranscodeBin
710    * @source: source element
711    *
712    * This signal is emitted after the source element has been created, so
713    * it can be configured by setting additional properties (e.g. set a
714    * proxy server for an http source, or set the device and read speed for
715    * an audio cd source). This is functionally equivalent to connecting to
716    * the notify::source signal, but more convenient.
717    *
718    * This signal is usually emitted from the context of a GStreamer streaming
719    * thread.
720    *
721    * Since: 1.20
722    */
723   signals[SIGNAL_SOURCE_SETUP] =
724       g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
725       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
726 
727   /**
728    * GstUriTranscodeBin::element-setup:
729    * @uritranscodebin: a #GstUriTranscodeBin
730    * @element: an element that was added to the uritranscodebin hierarchy
731    *
732    * This signal is emitted when a new element is added to uritranscodebin or any of
733    * its sub-bins. This signal can be used to configure elements, e.g. to set
734    * properties on decoders. This is functionally equivalent to connecting to
735    * the deep-element-added signal, but more convenient.
736    *
737    * This signal is usually emitted from the context of a GStreamer streaming
738    * thread, so might be called at the same time as code running in the main
739    * application thread.
740    *
741    * Since: 1.20
742    */
743   signals[SIGNAL_ELEMENT_SETUP] =
744       g_signal_new ("element-setup", G_TYPE_FROM_CLASS (klass),
745       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
746 }
747 
748 static void
gst_uri_transcode_bin_init(GstUriTranscodeBin * self)749 gst_uri_transcode_bin_init (GstUriTranscodeBin * self)
750 {
751   self->wanted_cpu_usage = 100;
752 }
753