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