1 /* GStreamer encoding bin
2 * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
3 * (C) 2009 Nokia Corporation
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
26 #include "gstencodebin.h"
27 #include "gstsmartencoder.h"
28 #include "gststreamsplitter.h"
29 #include "gststreamcombiner.h"
30 #include <gst/gst-i18n-plugin.h>
33 * SECTION:element-encodebin
36 * EncodeBin provides a bin for encoding/muxing various streams according to
37 * a specified #GstEncodingProfile.
39 * Based on the profile that was set (via the #GstEncodeBin:profile property),
40 * EncodeBin will internally select and configure the required elements
41 * (encoders, muxers, but also audio and video converters) so that you can
42 * provide it raw or pre-encoded streams of data in input and have your
43 * encoded/muxed/converted stream in output.
47 * * Automatic encoder and muxer selection based on elements available on the
50 * * Conversion of raw audio/video streams (scaling, framerate conversion,
51 * colorspace conversion, samplerate conversion) to conform to the profile
54 * * Variable number of streams. If the presence property for a stream encoding
55 * profile is 0, you can request any number of sink pads for it via the
56 * standard request pad gstreamer API or the #GstEncodeBin::request-pad action
59 * * Avoid reencoding (passthrough). If the input stream is already encoded and is
60 * compatible with what the #GstEncodingProfile expects, then the stream won't
61 * be re-encoded but just passed through downstream to the muxer or the output.
63 * * Mix pre-encoded and raw streams as input. In addition to the passthrough
64 * feature above, you can feed both raw audio/video *AND* already-encoded data
65 * to a pad. #GstEncodeBin will take care of passing through the compatible
66 * segments and re-encoding the segments of media that need encoding.
68 * * Standard behaviour is to use a #GstEncodingContainerProfile to have both
69 * encoding and muxing performed. But you can also provide a single stream
70 * profile (like #GstEncodingAudioProfile) to only have the encoding done and
71 * handle the encoded output yourself.
73 * * Audio imperfection corrections. Incoming audio streams can have non perfect
74 * timestamps (jitter), like the streams coming from ASF files. #GstEncodeBin
75 * will automatically fix those imperfections for you. See
76 * #GstEncodeBin:audio-jitter-tolerance for more details.
78 * * Variable or Constant video framerate. If your #GstEncodingVideoProfile has
79 * the variableframerate property deactivated (default), then the incoming
80 * raw video stream will be retimestampped in order to produce a constant
83 * * Cross-boundary re-encoding. When feeding compatible pre-encoded streams that
84 * fall on segment boundaries, and for supported formats (right now only H263),
85 * the GOP will be decoded/reencoded when needed to produce an encoded output
86 * that fits exactly within the request GstSegment.
88 * * Missing plugin support. If a #GstElement is missing to encode/mux to the
89 * request profile formats, a missing-plugin #GstMessage will be posted on the
90 * #GstBus, allowing systems that support the missing-plugin system to offer the
91 * user a way to install the missing element.
98 * Handling mp3!xing!idv3 and theora!ogg tagsetting scenarios:
99 * Once we have chosen a muxer:
100 * When a new stream is requested:
101 * If muxer isn't 'Formatter' OR doesn't have a TagSetter interface:
102 * Find a Formatter for the given stream (preferably with TagSetter)
103 * Insert that before muxer
106 #define fast_pad_link(a,b) gst_pad_link_full((a),(b),GST_PAD_LINK_CHECK_NOTHING)
107 #define fast_element_link(a,b) gst_element_link_pads_full((a),"src",(b),"sink",GST_PAD_LINK_CHECK_NOTHING)
111 GST_ENCODEBIN_FLAG_NO_AUDIO_CONVERSION = (1 << 0),
112 GST_ENCODEBIN_FLAG_NO_VIDEO_CONVERSION = (1 << 1)
115 #define GST_TYPE_ENCODEBIN_FLAGS (gst_encodebin_flags_get_type())
116 GType gst_encodebin_flags_get_type (void);
118 /* generic templates */
119 static GstStaticPadTemplate muxer_src_template =
120 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
121 GST_STATIC_CAPS_ANY);
123 static GstStaticPadTemplate video_sink_template =
124 GST_STATIC_PAD_TEMPLATE ("video_%u",
127 GST_STATIC_CAPS_ANY);
128 static GstStaticPadTemplate audio_sink_template =
129 GST_STATIC_PAD_TEMPLATE ("audio_%u",
132 GST_STATIC_CAPS_ANY);
133 /* static GstStaticPadTemplate text_sink_template = */
134 /* GST_STATIC_PAD_TEMPLATE ("text_%u", */
136 /* GST_PAD_REQUEST, */
137 /* GST_STATIC_CAPS_ANY); */
138 static GstStaticPadTemplate private_sink_template =
139 GST_STATIC_PAD_TEMPLATE ("private_%u",
142 GST_STATIC_CAPS_ANY);
148 /* the profile field is only valid if it could be entirely setup */
149 GstEncodingProfile *profile;
151 GList *streams; /* List of StreamGroup, not sorted */
154 /* Ghostpad with changing target */
157 /* TRUE if in PAUSED/PLAYING */
160 /* available muxers, encoders and parsers */
166 /* Increasing counter for unique pad name */
169 /* Cached caps for identification */
170 GstCaps *raw_video_caps;
171 GstCaps *raw_audio_caps;
172 /* GstCaps *raw_text_caps; */
174 guint queue_buffers_max;
175 guint queue_bytes_max;
176 guint64 queue_time_max;
179 gboolean avoid_reencoding;
181 GstEncodeBinFlags flags;
184 struct _GstEncodeBinClass
189 GstPad *(*request_pad) (GstEncodeBin * encodebin, GstCaps * caps);
190 GstPad *(*request_profile_pad) (GstEncodeBin * encodebin,
191 const gchar * profilename);
194 typedef struct _StreamGroup StreamGroup;
199 GstEncodingProfile *profile;
200 GstPad *ghostpad; /* Sink ghostpad */
201 GstElement *identity; /* Identity just after the ghostpad */
202 GstElement *inqueue; /* Queue just after the identity */
203 GstElement *splitter;
204 GList *converters; /* List of conversion GstElement */
205 GstElement *capsfilter; /* profile->restriction (if non-NULL/ANY) */
206 gulong inputfilter_caps_sid;
207 GstElement *encoder; /* Encoder (can be NULL) */
208 GstElement *fakesink; /* Fakesink (can be NULL) */
209 GstElement *combiner;
211 GstElement *smartencoder;
212 GstElement *outfilter; /* Output capsfilter (streamprofile.format) */
213 gulong outputfilter_caps_sid;
214 GstElement *formatter;
215 GstElement *outqueue; /* Queue just before the muxer */
216 gulong restriction_sid;
219 /* Default for queues (same defaults as queue element) */
220 #define DEFAULT_QUEUE_BUFFERS_MAX 200
221 #define DEFAULT_QUEUE_BYTES_MAX 10 * 1024 * 1024
222 #define DEFAULT_QUEUE_TIME_MAX GST_SECOND
223 #define DEFAULT_AUDIO_JITTER_TOLERANCE 20 * GST_MSECOND
224 #define DEFAULT_AVOID_REENCODING FALSE
225 #define DEFAULT_FLAGS 0
227 #define DEFAULT_RAW_CAPS \
231 "subpicture/x-dvd; " \
239 PROP_QUEUE_BUFFERS_MAX,
240 PROP_QUEUE_BYTES_MAX,
242 PROP_AUDIO_JITTER_TOLERANCE,
243 PROP_AVOID_REENCODING,
251 SIGNAL_REQUEST_PROFILE_PAD,
255 #define C_FLAGS(v) ((guint) v)
258 gst_encodebin_flags_get_type (void)
260 static const GFlagsValue values[] = {
261 {C_FLAGS (GST_ENCODEBIN_FLAG_NO_AUDIO_CONVERSION), "Do not use audio "
262 "conversion elements", "no-audio-conversion"},
263 {C_FLAGS (GST_ENCODEBIN_FLAG_NO_VIDEO_CONVERSION), "Do not use video "
264 "conversion elements", "no-video-conversion"},
267 static volatile GType id = 0;
269 if (g_once_init_enter ((gsize *) & id)) {
272 _id = g_flags_register_static ("GstEncodeBinFlags", values);
274 g_once_init_leave ((gsize *) & id, _id);
280 static guint gst_encode_bin_signals[LAST_SIGNAL] = { 0 };
282 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
284 GST_DEBUG_CATEGORY_STATIC (gst_encode_bin_debug);
285 #define GST_CAT_DEFAULT gst_encode_bin_debug
287 G_DEFINE_TYPE (GstEncodeBin, gst_encode_bin, GST_TYPE_BIN);
289 static void gst_encode_bin_dispose (GObject * object);
290 static void gst_encode_bin_set_property (GObject * object, guint prop_id,
291 const GValue * value, GParamSpec * pspec);
292 static void gst_encode_bin_get_property (GObject * object, guint prop_id,
293 GValue * value, GParamSpec * pspec);
294 static GstStateChangeReturn gst_encode_bin_change_state (GstElement * element,
295 GstStateChange transition);
297 static GstPad *gst_encode_bin_request_new_pad (GstElement * element,
298 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
299 static void gst_encode_bin_release_pad (GstElement * element, GstPad * pad);
302 gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile);
303 static void gst_encode_bin_tear_down_profile (GstEncodeBin * ebin);
304 static gboolean gst_encode_bin_setup_profile (GstEncodeBin * ebin,
305 GstEncodingProfile * profile);
307 static StreamGroup *_create_stream_group (GstEncodeBin * ebin,
308 GstEncodingProfile * sprof, const gchar * sinkpadname, GstCaps * sinkcaps,
309 gboolean * encoder_not_found);
310 static void stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup);
311 static void stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup);
312 static GstPad *gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin,
314 static GstPad *gst_encode_bin_request_profile_pad_signal (GstEncodeBin *
315 encodebin, const gchar * profilename);
317 static inline GstElement *_get_formatter (GstEncodeBin * ebin,
318 GstEncodingProfile * sprof);
319 static void _post_missing_plugin_message (GstEncodeBin * ebin,
320 GstEncodingProfile * prof);
323 gst_encode_bin_class_init (GstEncodeBinClass * klass)
325 GObjectClass *gobject_klass;
326 GstElementClass *gstelement_klass;
328 gobject_klass = (GObjectClass *) klass;
329 gstelement_klass = (GstElementClass *) klass;
331 gobject_klass->dispose = gst_encode_bin_dispose;
332 gobject_klass->set_property = gst_encode_bin_set_property;
333 gobject_klass->get_property = gst_encode_bin_get_property;
338 * GstEncodeBin:profile:
340 * The #GstEncodingProfile to use. This property must be set before going
341 * to %GST_STATE_PAUSED or higher.
343 g_object_class_install_property (gobject_klass, PROP_PROFILE,
344 g_param_spec_object ("profile", "Profile",
345 "The GstEncodingProfile to use", GST_TYPE_ENCODING_PROFILE,
346 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
348 g_object_class_install_property (gobject_klass, PROP_QUEUE_BYTES_MAX,
349 g_param_spec_uint ("queue-bytes-max", "Max. size (kB)",
350 "Max. amount of data in the queue (bytes, 0=disable)",
351 0, G_MAXUINT, DEFAULT_QUEUE_BYTES_MAX,
352 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
354 g_object_class_install_property (gobject_klass, PROP_QUEUE_BUFFERS_MAX,
355 g_param_spec_uint ("queue-buffers-max", "Max. size (buffers)",
356 "Max. number of buffers in the queue (0=disable)", 0, G_MAXUINT,
357 DEFAULT_QUEUE_BUFFERS_MAX,
358 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
360 g_object_class_install_property (gobject_klass, PROP_QUEUE_TIME_MAX,
361 g_param_spec_uint64 ("queue-time-max", "Max. size (ns)",
362 "Max. amount of data in the queue (in ns, 0=disable)", 0, G_MAXUINT64,
363 DEFAULT_QUEUE_TIME_MAX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
365 g_object_class_install_property (gobject_klass, PROP_AUDIO_JITTER_TOLERANCE,
366 g_param_spec_uint64 ("audio-jitter-tolerance", "Audio jitter tolerance",
367 "Amount of timestamp jitter/imperfection to allow on audio streams before inserting/dropping samples (ns)",
368 0, G_MAXUINT64, DEFAULT_AUDIO_JITTER_TOLERANCE,
369 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
371 g_object_class_install_property (gobject_klass, PROP_AVOID_REENCODING,
372 g_param_spec_boolean ("avoid-reencoding", "Avoid re-encoding",
373 "Whether to re-encode portions of compatible video streams that lay on segment boundaries",
374 DEFAULT_AVOID_REENCODING,
375 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
380 * Control the behaviour of encodebin.
382 g_object_class_install_property (gobject_klass, PROP_FLAGS,
383 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
384 GST_TYPE_ENCODEBIN_FLAGS, DEFAULT_FLAGS,
385 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
389 * GstEncodeBin::request-pad
390 * @encodebin: a #GstEncodeBin instance
393 * Use this method to request an unused sink request #GstPad that can take the
394 * provided @caps as input. You must release the pad with
395 * gst_element_release_request_pad() when you are done with it.
397 * Returns: A compatible #GstPad, or %NULL if no compatible #GstPad could be
398 * created or is available.
400 gst_encode_bin_signals[SIGNAL_REQUEST_PAD] =
401 g_signal_new ("request-pad", G_TYPE_FROM_CLASS (klass),
402 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstEncodeBinClass,
403 request_pad), NULL, NULL, NULL, GST_TYPE_PAD, 1, GST_TYPE_CAPS);
406 * GstEncodeBin::request-profile-pad
407 * @encodebin: a #GstEncodeBin instance
408 * @profilename: the name of a #GstEncodingProfile
410 * Use this method to request an unused sink request #GstPad from the profile
411 * @profilename. You must release the pad with
412 * gst_element_release_request_pad() when you are done with it.
414 * Returns: A compatible #GstPad, or %NULL if no compatible #GstPad could be
415 * created or is available.
417 gst_encode_bin_signals[SIGNAL_REQUEST_PROFILE_PAD] =
418 g_signal_new ("request-profile-pad", G_TYPE_FROM_CLASS (klass),
419 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstEncodeBinClass,
420 request_profile_pad), NULL, NULL, NULL, GST_TYPE_PAD, 1,
423 klass->request_pad = gst_encode_bin_request_pad_signal;
424 klass->request_profile_pad = gst_encode_bin_request_profile_pad_signal;
426 gst_element_class_add_static_pad_template (gstelement_klass,
427 &muxer_src_template);
428 gst_element_class_add_static_pad_template (gstelement_klass,
429 &video_sink_template);
430 gst_element_class_add_static_pad_template (gstelement_klass,
431 &audio_sink_template);
432 /* gst_element_class_add_static_pad_template (gstelement_klass, &text_sink_template); */
433 gst_element_class_add_static_pad_template (gstelement_klass,
434 &private_sink_template);
436 gstelement_klass->change_state =
437 GST_DEBUG_FUNCPTR (gst_encode_bin_change_state);
438 gstelement_klass->request_new_pad =
439 GST_DEBUG_FUNCPTR (gst_encode_bin_request_new_pad);
440 gstelement_klass->release_pad =
441 GST_DEBUG_FUNCPTR (gst_encode_bin_release_pad);
443 gst_element_class_set_static_metadata (gstelement_klass,
445 "Generic/Bin/Encoder",
446 "Convenience encoding/muxing element",
447 "Edward Hervey <edward.hervey@collabora.co.uk>");
449 gst_type_mark_as_plugin_api (GST_TYPE_ENCODEBIN_FLAGS, 0);
453 gst_encode_bin_dispose (GObject * object)
455 GstEncodeBin *ebin = (GstEncodeBin *) object;
458 gst_plugin_feature_list_free (ebin->muxers);
461 if (ebin->formatters)
462 gst_plugin_feature_list_free (ebin->formatters);
463 ebin->formatters = NULL;
466 gst_plugin_feature_list_free (ebin->encoders);
467 ebin->encoders = NULL;
470 gst_plugin_feature_list_free (ebin->parsers);
471 ebin->parsers = NULL;
473 gst_encode_bin_tear_down_profile (ebin);
475 if (ebin->raw_video_caps)
476 gst_caps_unref (ebin->raw_video_caps);
477 ebin->raw_video_caps = NULL;
478 if (ebin->raw_audio_caps)
479 gst_caps_unref (ebin->raw_audio_caps);
480 ebin->raw_audio_caps = NULL;
481 /* if (ebin->raw_text_caps) */
482 /* gst_caps_unref (ebin->raw_text_caps); */
484 G_OBJECT_CLASS (gst_encode_bin_parent_class)->dispose (object);
488 gst_encode_bin_init (GstEncodeBin * encode_bin)
490 GstPadTemplate *tmpl;
493 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER,
496 encode_bin->formatters =
497 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_FORMATTER,
500 encode_bin->encoders =
501 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER,
504 encode_bin->parsers =
505 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER,
508 encode_bin->raw_video_caps = gst_caps_from_string ("video/x-raw");
509 encode_bin->raw_audio_caps = gst_caps_from_string ("audio/x-raw");
510 /* encode_bin->raw_text_caps = */
511 /* gst_caps_from_string ("text/x-raw"); */
513 encode_bin->queue_buffers_max = DEFAULT_QUEUE_BUFFERS_MAX;
514 encode_bin->queue_bytes_max = DEFAULT_QUEUE_BYTES_MAX;
515 encode_bin->queue_time_max = DEFAULT_QUEUE_TIME_MAX;
516 encode_bin->tolerance = DEFAULT_AUDIO_JITTER_TOLERANCE;
517 encode_bin->avoid_reencoding = DEFAULT_AVOID_REENCODING;
518 encode_bin->flags = DEFAULT_FLAGS;
520 tmpl = gst_static_pad_template_get (&muxer_src_template);
521 encode_bin->srcpad = gst_ghost_pad_new_no_target_from_template ("src", tmpl);
522 gst_object_unref (tmpl);
523 gst_pad_set_active (encode_bin->srcpad, TRUE);
524 gst_element_add_pad (GST_ELEMENT_CAST (encode_bin), encode_bin->srcpad);
528 gst_encode_bin_set_property (GObject * object, guint prop_id,
529 const GValue * value, GParamSpec * pspec)
531 GstEncodeBin *ebin = (GstEncodeBin *) object;
535 gst_encode_bin_set_profile (ebin,
536 (GstEncodingProfile *) g_value_get_object (value));
538 case PROP_QUEUE_BUFFERS_MAX:
539 ebin->queue_buffers_max = g_value_get_uint (value);
541 case PROP_QUEUE_BYTES_MAX:
542 ebin->queue_bytes_max = g_value_get_uint (value);
544 case PROP_QUEUE_TIME_MAX:
545 ebin->queue_time_max = g_value_get_uint64 (value);
547 case PROP_AUDIO_JITTER_TOLERANCE:
548 ebin->tolerance = g_value_get_uint64 (value);
550 case PROP_AVOID_REENCODING:
551 ebin->avoid_reencoding = g_value_get_boolean (value);
554 ebin->flags = g_value_get_flags (value);
557 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
563 gst_encode_bin_get_property (GObject * object, guint prop_id,
564 GValue * value, GParamSpec * pspec)
566 GstEncodeBin *ebin = (GstEncodeBin *) object;
570 g_value_set_object (value, (GObject *) ebin->profile);
572 case PROP_QUEUE_BUFFERS_MAX:
573 g_value_set_uint (value, ebin->queue_buffers_max);
575 case PROP_QUEUE_BYTES_MAX:
576 g_value_set_uint (value, ebin->queue_bytes_max);
578 case PROP_QUEUE_TIME_MAX:
579 g_value_set_uint64 (value, ebin->queue_time_max);
581 case PROP_AUDIO_JITTER_TOLERANCE:
582 g_value_set_uint64 (value, ebin->tolerance);
584 case PROP_AVOID_REENCODING:
585 g_value_set_boolean (value, ebin->avoid_reencoding);
588 g_value_set_flags (value, ebin->flags);
591 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
596 static inline gboolean
597 are_raw_caps (const GstCaps * caps)
599 GstCaps *raw = gst_static_caps_get (&default_raw_caps);
600 gboolean res = gst_caps_can_intersect (caps, raw);
602 gst_caps_unref (raw);
606 /* Returns the number of time a given stream profile is currently used
609 stream_profile_used_count (GstEncodeBin * ebin, GstEncodingProfile * sprof)
611 guint nbprofused = 0;
614 for (tmp = ebin->streams; tmp; tmp = tmp->next) {
615 StreamGroup *sgroup = (StreamGroup *) tmp->data;
617 if (sgroup->profile == sprof)
624 static inline GstEncodingProfile *
625 next_unused_stream_profile (GstEncodeBin * ebin, GType ptype,
626 const gchar * name, GstCaps * caps, GstEncodingProfile * previous_profile)
628 GST_DEBUG_OBJECT (ebin, "ptype:%s, caps:%" GST_PTR_FORMAT,
629 g_type_name (ptype), caps);
631 if (G_UNLIKELY (ptype == G_TYPE_NONE && caps != NULL)) {
632 /* Identify the profile type based on raw caps */
633 if (gst_caps_can_intersect (ebin->raw_video_caps, caps))
634 ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
635 else if (gst_caps_can_intersect (ebin->raw_audio_caps, caps))
636 ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
637 /* else if (gst_caps_can_intersect (ebin->raw_text_caps, caps)) */
638 /* ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
639 GST_DEBUG_OBJECT (ebin, "Detected profile type as being %s",
640 g_type_name (ptype));
643 if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
647 /* If we have a name, try to find a profile with the same name */
649 gst_encoding_container_profile_get_profiles
650 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
652 for (; tmp; tmp = tmp->next) {
653 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
654 const gchar *profilename = gst_encoding_profile_get_name (sprof);
656 if (profilename && !strcmp (name, profilename)) {
657 guint presence = gst_encoding_profile_get_presence (sprof);
659 GST_DEBUG ("Found profile matching the requested name");
661 if (!gst_encoding_profile_is_enabled (sprof)) {
662 GST_INFO_OBJECT (ebin, "%p is disabled, not using it", sprof);
668 || presence > stream_profile_used_count (ebin, sprof))
671 GST_WARNING ("Matching stream already used");
676 ("No profiles matching requested pad name, carrying on with normal stream matching");
680 gst_encoding_container_profile_get_profiles
681 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile)); tmp;
683 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
685 /* Pick an available Stream profile for which:
686 * * either it is of the compatible raw type,
687 * * OR we can pass it through directly without encoding
689 if (G_TYPE_FROM_INSTANCE (sprof) == ptype) {
690 guint presence = gst_encoding_profile_get_presence (sprof);
691 GST_DEBUG ("Found a stream profile with the same type");
692 if (!gst_encoding_profile_is_enabled (sprof)) {
693 GST_INFO_OBJECT (ebin, "%p is disabled, not using it", sprof);
694 } else if (presence == 0
695 || (presence > stream_profile_used_count (ebin, sprof))) {
697 if (sprof != previous_profile)
700 } else if (caps && ptype == G_TYPE_NONE) {
704 outcaps = gst_encoding_profile_get_input_caps (sprof);
705 GST_DEBUG ("Unknown stream, seeing if it's compatible with %"
706 GST_PTR_FORMAT, outcaps);
707 res = gst_caps_can_intersect (outcaps, caps);
708 gst_caps_unref (outcaps);
710 if (res && sprof != previous_profile)
720 request_pad_for_stream (GstEncodeBin * encodebin, GType ptype,
721 const gchar * name, GstCaps * caps)
723 StreamGroup *sgroup = NULL;
724 GList *not_found_encoder_profs = NULL, *tmp;
725 GstEncodingProfile *sprof = NULL;
727 GST_DEBUG_OBJECT (encodebin, "name:%s caps:%" GST_PTR_FORMAT, name, caps);
729 while (sgroup == NULL) {
730 gboolean encoder_not_found = FALSE;
731 /* Figure out if we have a unused GstEncodingProfile we can use for
733 sprof = next_unused_stream_profile (encodebin, ptype, name, caps, sprof);
735 if (G_UNLIKELY (sprof == NULL))
736 goto no_stream_profile;
738 sgroup = _create_stream_group (encodebin, sprof, name, caps,
741 if (G_UNLIKELY (sgroup))
744 if (encoder_not_found) {
745 not_found_encoder_profs = g_list_prepend (not_found_encoder_profs, sprof);
747 GST_DEBUG ("Could not create an encoder for %s", name);
748 goto no_stream_group;
756 goto no_stream_group;
758 g_list_free (not_found_encoder_profs);
759 return sgroup->ghostpad;
763 GST_WARNING_OBJECT (encodebin, "Couldn't find a compatible stream profile");
769 for (tmp = not_found_encoder_profs; tmp; tmp = tmp->next)
770 _post_missing_plugin_message (encodebin, tmp->data);
771 g_list_free (not_found_encoder_profs);
773 GST_WARNING_OBJECT (encodebin, "Couldn't create a StreamGroup");
779 gst_encode_bin_request_new_pad (GstElement * element,
780 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
782 GstEncodeBin *ebin = (GstEncodeBin *) element;
785 GST_DEBUG_OBJECT (element, "templ:%s, name:%s", templ->name_template, name);
787 /* Identify the stream group (if name or caps have been provided) */
788 if (caps != NULL || name != NULL) {
789 res = request_pad_for_stream (ebin, G_TYPE_NONE, name, (GstCaps *) caps);
793 GType ptype = G_TYPE_NONE;
795 if (!strcmp (templ->name_template, "video_%u"))
796 ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
797 else if (!strcmp (templ->name_template, "audio_%u"))
798 ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
799 /* else if (!strcmp (templ->name_template, "text_%u")) */
800 /* ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
802 /* FIXME : Check uniqueness of pad */
803 /* FIXME : Check that the requested number is the last one, and if not,
804 * update the last_pad_id variable so that we don't create a pad with
805 * the same name/number in the future */
807 res = request_pad_for_stream (ebin, ptype, name, NULL);
814 gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin, GstCaps * caps)
816 GstPad *pad = request_pad_for_stream (encodebin, G_TYPE_NONE, NULL, caps);
818 return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL;
822 gst_encode_bin_request_profile_pad_signal (GstEncodeBin * encodebin,
823 const gchar * profilename)
826 request_pad_for_stream (encodebin, G_TYPE_NONE, profilename, NULL);
828 return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL;
831 static inline StreamGroup *
832 find_stream_group_from_pad (GstEncodeBin * ebin, GstPad * pad)
836 for (tmp = ebin->streams; tmp; tmp = tmp->next) {
837 StreamGroup *sgroup = (StreamGroup *) tmp->data;
838 if (G_UNLIKELY (sgroup->ghostpad == pad))
846 gst_encode_bin_release_pad (GstElement * element, GstPad * pad)
848 GstEncodeBin *ebin = (GstEncodeBin *) element;
851 /* Find the associated StreamGroup */
853 sgroup = find_stream_group_from_pad (ebin, pad);
854 if (G_UNLIKELY (sgroup == NULL))
855 goto no_stream_group;
857 /* Release objects/data associated with the StreamGroup */
858 stream_group_remove (ebin, sgroup);
864 GST_WARNING_OBJECT (ebin, "Couldn't find corresponding StreamGroup");
869 /* Create a parser for the given stream profile */
870 static inline GstElement *
871 _get_parser (GstEncodeBin * ebin, GstEncodingProfile * sprof)
873 GList *parsers1, *parsers, *tmp;
874 GstElement *parser = NULL;
875 GstElementFactory *parserfact = NULL;
878 format = gst_encoding_profile_get_format (sprof);
880 GST_DEBUG ("Getting list of parsers for format %" GST_PTR_FORMAT, format);
882 /* FIXME : requesting twice the parsers twice is a bit ugly, we should
883 * have a method to request on more than one condition */
885 gst_element_factory_list_filter (ebin->parsers, format,
888 gst_element_factory_list_filter (parsers1, format, GST_PAD_SINK, FALSE);
889 gst_plugin_feature_list_free (parsers1);
891 if (G_UNLIKELY (parsers == NULL)) {
892 GST_DEBUG ("Couldn't find any compatible parsers");
896 for (tmp = parsers; tmp; tmp = tmp->next) {
897 /* FIXME : We're only picking the first one so far */
898 /* FIXME : signal the user if he wants this */
899 parserfact = (GstElementFactory *) tmp->data;
904 parser = gst_element_factory_create (parserfact, NULL);
906 gst_plugin_feature_list_free (parsers);
910 gst_caps_unref (format);
916 _create_element_and_set_preset (GstElementFactory * factory,
917 const gchar * preset, const gchar * name, const gchar * preset_name)
919 GstElement *res = NULL;
921 GST_DEBUG ("Creating element from factory %s (preset factory name: %s"
922 " preset name: %s)", GST_OBJECT_NAME (factory), preset_name, preset);
924 if (preset_name && g_strcmp0 (GST_OBJECT_NAME (factory), preset_name)) {
925 GST_DEBUG ("Got to use %s, not %s", preset_name, GST_OBJECT_NAME (factory));
929 res = gst_element_factory_create (factory, name);
931 if (preset && GST_IS_PRESET (res)) {
932 if (preset_name == NULL ||
933 g_strcmp0 (GST_OBJECT_NAME (factory), preset_name) == 0) {
935 if (!gst_preset_load_preset (GST_PRESET (res), preset)) {
936 GST_WARNING ("Couldn't set preset [%s] on element [%s]",
937 preset, GST_OBJECT_NAME (factory));
938 gst_object_unref (res);
942 GST_DEBUG ("Using a preset with no preset name, making use of the"
943 " proper element without setting any property");
946 /* Else we keep it */
951 /* Create the encoder for the given stream profile */
952 static inline GstElement *
953 _get_encoder (GstEncodeBin * ebin, GstEncodingProfile * sprof)
955 GList *encoders, *tmp;
956 GstElement *encoder = NULL;
957 GstElementFactory *encoderfact = NULL;
959 const gchar *preset, *preset_name;
961 format = gst_encoding_profile_get_format (sprof);
962 preset = gst_encoding_profile_get_preset (sprof);
963 preset_name = gst_encoding_profile_get_preset_name (sprof);
965 GST_DEBUG ("Getting list of encoders for format %" GST_PTR_FORMAT, format);
967 /* If stream caps are raw, return identity */
968 if (G_UNLIKELY (are_raw_caps (format))) {
969 GST_DEBUG ("Stream format is raw, returning identity as the encoder");
970 encoder = gst_element_factory_make ("identity", NULL);
975 gst_element_factory_list_filter (ebin->encoders, format,
978 if (G_UNLIKELY (encoders == NULL) && sprof == ebin->profile) {
979 /* Special case: if the top-level profile is an encoder,
980 * it could be listed in our muxers (for example wavenc)
982 encoders = gst_element_factory_list_filter (ebin->muxers, format,
986 if (G_UNLIKELY (encoders == NULL)) {
987 GST_DEBUG ("Couldn't find any compatible encoders");
991 for (tmp = encoders; tmp; tmp = tmp->next) {
992 encoderfact = (GstElementFactory *) tmp->data;
993 if ((encoder = _create_element_and_set_preset (encoderfact, preset,
998 gst_plugin_feature_list_free (encoders);
1002 gst_caps_unref (format);
1008 local_element_request_pad (GstElement * element, GstPadTemplate * templ,
1009 const gchar * name, const GstCaps * caps)
1011 GstPad *newpad = NULL;
1012 GstElementClass *oclass;
1014 oclass = GST_ELEMENT_GET_CLASS (element);
1016 if (oclass->request_new_pad)
1017 newpad = (oclass->request_new_pad) (element, templ, name, caps);
1020 gst_object_ref (newpad);
1026 gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
1029 GstPadPresence presence;
1031 /* If this function is ever exported, we need check the validity of `element'
1032 * and `templ', and to make sure the template actually belongs to the
1035 presence = GST_PAD_TEMPLATE_PRESENCE (templ);
1038 case GST_PAD_ALWAYS:
1039 case GST_PAD_SOMETIMES:
1040 ret = gst_element_get_static_pad (element, templ->name_template);
1041 if (!ret && presence == GST_PAD_ALWAYS)
1043 ("Element %s has an ALWAYS template %s, but no pad of the same name",
1044 GST_OBJECT_NAME (element), templ->name_template);
1047 case GST_PAD_REQUEST:
1048 ret = gst_element_request_pad (element, templ, NULL, NULL);
1055 /* FIXME : Improve algorithm for finding compatible muxer sink pad */
1056 static inline GstPad *
1057 get_compatible_muxer_sink_pad (GstEncodeBin * ebin, GstElement * encoder,
1061 GstPadTemplate *srctempl = NULL;
1062 GstPadTemplate *sinktempl;
1066 srcpad = gst_element_get_static_pad (encoder, "src");
1068 srctempl = gst_pad_get_pad_template (srcpad);
1070 GST_DEBUG_OBJECT (ebin,
1071 "Attempting to find pad from muxer %s compatible with %s:%s",
1072 GST_ELEMENT_NAME (ebin->muxer), GST_DEBUG_PAD_NAME (srcpad));
1074 gst_object_unref (srcpad);
1075 sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
1076 gst_object_unref (srctempl);
1079 gst_pad_template_new ("whatever", GST_PAD_SRC, GST_PAD_ALWAYS,
1081 g_assert (srctempl != NULL);
1082 sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
1083 gst_object_unref (srctempl);
1086 if (G_UNLIKELY (sinktempl == NULL))
1089 sinkpad = gst_element_get_pad_from_template (ebin->muxer, sinktempl);
1095 GST_WARNING_OBJECT (ebin, "No compatible pad available on muxer");
1101 _has_class (GstElement * element, const gchar * classname)
1103 GstElementClass *klass;
1106 klass = GST_ELEMENT_GET_CLASS (element);
1107 value = gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS);
1111 return strstr (value, classname) != NULL;
1115 _profile_restriction_caps_cb (GstEncodingProfile * profile,
1116 GParamSpec * arg G_GNUC_UNUSED, StreamGroup * group)
1118 GstCaps *restriction = gst_encoding_profile_get_restriction (profile);
1120 g_object_set (group->capsfilter, "caps", restriction, NULL);
1124 _capsfilter_force_format (GstPad * pad,
1125 GParamSpec * arg G_GNUC_UNUSED, gulong * signal_id)
1128 GstStructure *structure;
1130 g_object_get (pad, "caps", &caps, NULL);
1131 caps = gst_caps_copy (caps);
1133 structure = gst_caps_get_structure (caps, 0);
1134 gst_structure_remove_field (structure, "streamheader");
1135 GST_INFO_OBJECT (pad, "Forcing caps to %" GST_PTR_FORMAT, caps);
1136 g_object_set (GST_OBJECT_PARENT (pad), "caps", caps, NULL);
1137 g_signal_handler_disconnect (pad, *signal_id);
1139 gst_caps_unref (caps);
1143 _set_group_caps_format (StreamGroup * sgroup, GstEncodingProfile * prof,
1146 g_object_set (sgroup->outfilter, "caps", format, NULL);
1148 if (!gst_encoding_profile_get_allow_dynamic_output (prof)) {
1149 if (!sgroup->outputfilter_caps_sid) {
1150 sgroup->outputfilter_caps_sid =
1151 g_signal_connect (sgroup->outfilter->sinkpads->data,
1152 "notify::caps", G_CALLBACK (_capsfilter_force_format),
1153 &sgroup->outputfilter_caps_sid);
1159 _post_missing_plugin_message (GstEncodeBin * ebin, GstEncodingProfile * prof)
1162 format = gst_encoding_profile_get_format (prof);
1164 GST_ERROR_OBJECT (ebin,
1165 "Couldn't create encoder with preset %s and preset name %s"
1166 " for format %" GST_PTR_FORMAT,
1167 GST_STR_NULL (gst_encoding_profile_get_preset (prof)),
1168 GST_STR_NULL (gst_encoding_profile_get_preset_name (prof)), format);
1170 /* missing plugin support */
1171 gst_element_post_message (GST_ELEMENT_CAST (ebin),
1172 gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format));
1173 GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN,
1174 ("Couldn't create encoder for format %" GST_PTR_FORMAT, format), (NULL));
1176 gst_caps_unref (format);
1179 static GstPadProbeReturn
1180 _missing_plugin_probe (GstPad * pad, GstPadProbeInfo * info, gpointer udata)
1182 StreamGroup *sgroup = udata;
1183 GstEncodeBin *ebin = sgroup->ebin;
1185 _post_missing_plugin_message (ebin, sgroup->profile);
1187 return GST_PAD_PROBE_OK;
1191 _set_up_fake_encoder_pad_probe (GstEncodeBin * ebin, StreamGroup * sgroup)
1193 GstPad *pad = gst_element_get_static_pad (sgroup->fakesink, "sink");
1195 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, _missing_plugin_probe,
1198 gst_object_unref (pad);
1201 /* FIXME : Add handling of streams that don't require conversion elements */
1203 * Create the elements, StreamGroup, add the sink pad, link it to the muxer
1205 * sinkpadname: If non-NULL, that name will be assigned to the sink ghost pad
1206 * sinkcaps: If non-NULL will be used to figure out how to setup the group
1207 * encoder_not_found: If non NULL, set to TRUE if failure happened because
1208 * the encoder could not be found
1210 static StreamGroup *
1211 _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
1212 const gchar * sinkpadname, GstCaps * sinkcaps, gboolean * encoder_not_found)
1214 StreamGroup *sgroup = NULL;
1215 GstPad *sinkpad, *srcpad = NULL, *muxerpad = NULL;
1216 /* Element we will link to the encoder */
1217 GstElement *last = NULL;
1218 GstElement *encoder = NULL;
1219 GList *tmp, *tosync = NULL;
1220 GstCaps *format, *restriction;
1221 const gchar *missing_element_name;
1223 format = gst_encoding_profile_get_format (sprof);
1224 restriction = gst_encoding_profile_get_restriction (sprof);
1226 GST_DEBUG ("Creating group. format %" GST_PTR_FORMAT ", for caps %"
1227 GST_PTR_FORMAT, format, sinkcaps);
1228 GST_DEBUG ("avoid_reencoding:%d", ebin->avoid_reencoding);
1230 sgroup = g_slice_new0 (StreamGroup);
1231 sgroup->ebin = ebin;
1232 sgroup->profile = sprof;
1234 /* NOTE for people reading this code:
1236 * We construct the group starting by the furthest downstream element
1237 * and making our way up adding/syncing/linking as we go.
1239 * There are two parallel paths:
1240 * * One for raw data which goes through converters and encoders
1241 * * One for already encoded data
1245 * If we are handling a container profile, figure out if the muxer has a
1246 * sinkpad compatible with the selected profile */
1248 muxerpad = get_compatible_muxer_sink_pad (ebin, NULL, format);
1249 if (G_UNLIKELY (muxerpad == NULL))
1255 * The actual queueing will be done in the input queue, but some queuing
1256 * after the encoder can be beneficial for encoding performance. */
1257 last = sgroup->outqueue = gst_element_factory_make ("queue", NULL);
1258 g_object_set (sgroup->outqueue, "max-size-buffers", (guint) 0,
1259 "max-size-bytes", (guint) 0, "max-size-time", (guint64) 3 * GST_SECOND,
1260 "silent", TRUE, NULL);
1262 gst_bin_add (GST_BIN (ebin), sgroup->outqueue);
1263 tosync = g_list_append (tosync, sgroup->outqueue);
1264 srcpad = gst_element_get_static_pad (sgroup->outqueue, "src");
1266 if (G_UNLIKELY (fast_pad_link (srcpad, muxerpad) != GST_PAD_LINK_OK)) {
1267 goto muxer_link_failure;
1269 gst_object_unref (muxerpad);
1271 gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), srcpad);
1273 gst_object_unref (srcpad);
1276 /* Check if we need a formatter
1277 * If we have no muxer or
1278 * if the muxer isn't a formatter and doesn't implement the tagsetter interface
1280 if (!ebin->muxer || (!GST_IS_TAG_SETTER (ebin->muxer)
1281 && !_has_class (ebin->muxer, "Formatter"))) {
1282 sgroup->formatter = _get_formatter (ebin, sprof);
1283 if (sgroup->formatter) {
1284 GST_DEBUG ("Adding formatter for %" GST_PTR_FORMAT, format);
1286 gst_bin_add (GST_BIN (ebin), sgroup->formatter);
1287 tosync = g_list_append (tosync, sgroup->formatter);
1288 if (G_UNLIKELY (!fast_element_link (sgroup->formatter, last)))
1289 goto formatter_link_failure;
1290 last = sgroup->formatter;
1295 /* Output capsfilter
1296 * This will receive the format caps from the streamprofile */
1297 GST_DEBUG ("Adding output capsfilter for %" GST_PTR_FORMAT, format);
1298 sgroup->outfilter = gst_element_factory_make ("capsfilter", NULL);
1299 _set_group_caps_format (sgroup, sprof, format);
1301 gst_bin_add (GST_BIN (ebin), sgroup->outfilter);
1302 tosync = g_list_append (tosync, sgroup->outfilter);
1303 if (G_UNLIKELY (!fast_element_link (sgroup->outfilter, last)))
1304 goto outfilter_link_failure;
1305 last = sgroup->outfilter;
1308 sgroup->parser = _get_parser (ebin, sprof);
1310 if (sgroup->parser != NULL) {
1311 GST_DEBUG ("Got a parser %s", GST_ELEMENT_NAME (sgroup->parser));
1312 gst_bin_add (GST_BIN (ebin), sgroup->parser);
1313 tosync = g_list_append (tosync, sgroup->parser);
1314 if (G_UNLIKELY (!gst_element_link (sgroup->parser, last)))
1315 goto parser_link_failure;
1316 last = sgroup->parser;
1319 /* Stream combiner */
1320 sgroup->combiner = g_object_new (GST_TYPE_STREAM_COMBINER, NULL);
1322 gst_bin_add (GST_BIN (ebin), sgroup->combiner);
1323 tosync = g_list_append (tosync, sgroup->combiner);
1324 if (G_UNLIKELY (!fast_element_link (sgroup->combiner, last)))
1325 goto combiner_link_failure;
1328 /* Stream splitter */
1329 sgroup->splitter = g_object_new (GST_TYPE_STREAM_SPLITTER, NULL);
1331 gst_bin_add (GST_BIN (ebin), sgroup->splitter);
1332 tosync = g_list_append (tosync, sgroup->splitter);
1334 if (gst_encoding_profile_get_single_segment (sprof)) {
1335 sgroup->identity = gst_element_factory_make ("identity", NULL);
1336 g_object_set (sgroup->identity, "single-segment", TRUE, NULL);
1337 gst_bin_add (GST_BIN (ebin), sgroup->identity);
1338 tosync = g_list_append (tosync, sgroup->identity);
1342 * FIXME : figure out what max-size to use for the input queue */
1343 sgroup->inqueue = gst_element_factory_make ("queue", NULL);
1344 g_object_set (sgroup->inqueue, "max-size-buffers",
1345 (guint) ebin->queue_buffers_max, "max-size-bytes",
1346 (guint) ebin->queue_bytes_max, "max-size-time",
1347 (guint64) ebin->queue_time_max, "silent", TRUE, NULL);
1349 gst_bin_add (GST_BIN (ebin), sgroup->inqueue);
1350 tosync = g_list_append (tosync, sgroup->inqueue);
1352 /* Expose input queue or identity sink pad as ghostpad */
1354 gst_element_get_static_pad (sgroup->identity ? sgroup->
1355 identity : sgroup->inqueue, "sink");
1356 if (sinkpadname == NULL) {
1358 g_strdup_printf ("%s_%u", gst_encoding_profile_get_type_nick (sprof),
1359 ebin->last_pad_id++);
1360 GST_DEBUG ("Adding ghost pad %s", pname);
1361 sgroup->ghostpad = gst_ghost_pad_new (pname, sinkpad);
1364 sgroup->ghostpad = gst_ghost_pad_new (sinkpadname, sinkpad);
1365 gst_object_unref (sinkpad);
1367 if (sgroup->identity
1368 && G_UNLIKELY (!fast_element_link (sgroup->identity, sgroup->inqueue)))
1369 goto queue_link_failure;
1371 if (G_UNLIKELY (!fast_element_link (sgroup->inqueue, sgroup->splitter)))
1372 goto splitter_link_failure;
1375 /* Path 1 : Already-encoded data */
1377 local_element_request_pad (sgroup->combiner, NULL, "passthroughsink",
1379 if (G_UNLIKELY (sinkpad == NULL))
1380 goto no_combiner_sinkpad;
1382 if (ebin->avoid_reencoding) {
1385 GST_DEBUG ("Asked to use Smart Encoder");
1386 sgroup->smartencoder = g_object_new (GST_TYPE_SMART_ENCODER, NULL);
1388 /* Check if stream format is compatible */
1389 srcpad = gst_element_get_static_pad (sgroup->smartencoder, "src");
1390 tmpcaps = gst_pad_query_caps (srcpad, NULL);
1391 if (!gst_caps_can_intersect (tmpcaps, format)) {
1392 GST_DEBUG ("We don't have a smart encoder for the stream format");
1393 gst_object_unref (sgroup->smartencoder);
1394 sgroup->smartencoder = NULL;
1396 gst_bin_add ((GstBin *) ebin, sgroup->smartencoder);
1397 fast_pad_link (srcpad, sinkpad);
1398 tosync = g_list_append (tosync, sgroup->smartencoder);
1399 sinkpad = gst_element_get_static_pad (sgroup->smartencoder, "sink");
1401 gst_caps_unref (tmpcaps);
1402 gst_object_unref (srcpad);
1406 local_element_request_pad (sgroup->splitter, NULL, "passthroughsrc",
1408 if (G_UNLIKELY (srcpad == NULL))
1409 goto no_splitter_srcpad;
1411 /* Go straight to splitter */
1412 if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1413 goto passthrough_link_failure;
1414 gst_object_unref (sinkpad);
1415 gst_object_unref (srcpad);
1418 /* Path 2 : Conversion / Encoding */
1420 /* 1. Create the encoder */
1421 GST_LOG ("Adding encoder");
1422 sgroup->encoder = _get_encoder (ebin, sprof);
1423 if (sgroup->encoder != NULL) {
1424 gst_bin_add ((GstBin *) ebin, sgroup->encoder);
1425 tosync = g_list_append (tosync, sgroup->encoder);
1428 local_element_request_pad (sgroup->combiner, NULL, "encodingsink",
1430 if (G_UNLIKELY (sinkpad == NULL))
1431 goto no_combiner_sinkpad;
1432 srcpad = gst_element_get_static_pad (sgroup->encoder, "src");
1433 if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1434 goto encoder_link_failure;
1435 gst_object_unref (sinkpad);
1436 gst_object_unref (srcpad);
1438 } else if (gst_encoding_profile_get_preset (sgroup->profile)
1439 || gst_encoding_profile_get_preset_name (sgroup->profile)) {
1441 if (!encoder_not_found)
1442 _post_missing_plugin_message (ebin, sprof);
1444 *encoder_not_found = TRUE;
1447 /* passthrough can still work, if we discover that *
1448 * encoding is required we post a missing plugin message */
1452 /* 3. Create the conversion/restriction elements */
1453 /* 3.1. capsfilter */
1454 GST_LOG ("Adding capsfilter for restriction caps : %" GST_PTR_FORMAT,
1457 last = sgroup->capsfilter = gst_element_factory_make ("capsfilter", NULL);
1458 if (restriction && !gst_caps_is_any (restriction))
1459 g_object_set (sgroup->capsfilter, "caps", restriction, NULL);
1461 if (!gst_encoding_profile_get_allow_dynamic_output (sprof)) {
1462 if (!sgroup->inputfilter_caps_sid) {
1463 sgroup->inputfilter_caps_sid =
1464 g_signal_connect (sgroup->capsfilter->sinkpads->data,
1465 "notify::caps", G_CALLBACK (_capsfilter_force_format),
1466 &sgroup->inputfilter_caps_sid);
1470 gst_bin_add ((GstBin *) ebin, sgroup->capsfilter);
1471 tosync = g_list_append (tosync, sgroup->capsfilter);
1472 if (sgroup->encoder == NULL) {
1473 /* no encoder available but it might be possible to just do passthrough, so
1474 * let's just set up a fake pad to detect that encoding was attempted and
1475 * if so it posts the missing plugin message */
1476 sgroup->fakesink = gst_element_factory_make ("fakesink", NULL);
1477 g_object_set (sgroup->fakesink, "async", FALSE, NULL);
1478 gst_bin_add (GST_BIN_CAST (ebin), sgroup->fakesink);
1479 tosync = g_list_append (tosync, sgroup->fakesink);
1480 encoder = sgroup->fakesink;
1482 _set_up_fake_encoder_pad_probe (ebin, sgroup);
1484 encoder = sgroup->encoder;
1486 fast_element_link (sgroup->capsfilter, encoder);
1487 sgroup->restriction_sid = g_signal_connect (sprof, "notify::restriction-caps",
1488 G_CALLBACK (_profile_restriction_caps_cb), sgroup);
1490 /* 3.2. restriction elements */
1491 /* FIXME : Once we have properties for specific converters, use those */
1492 if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
1493 const gboolean native_video =
1494 ! !(ebin->flags & GST_ENCODEBIN_FLAG_NO_VIDEO_CONVERSION);
1495 GstElement *cspace = NULL, *scale, *vrate, *cspace2 = NULL;
1497 GST_LOG ("Adding conversion elements for video stream");
1499 if (!native_video) {
1500 cspace = gst_element_factory_make ("videoconvert", NULL);
1501 scale = gst_element_factory_make ("videoscale", NULL);
1503 missing_element_name = "videoscale";
1504 goto missing_element;
1506 /* 4-tap scaling and black borders */
1507 g_object_set (scale, "method", 2, "add-borders", TRUE, NULL);
1508 cspace2 = gst_element_factory_make ("videoconvert", NULL);
1510 if (!cspace || !cspace2) {
1511 missing_element_name = "videoconvert";
1512 goto missing_element;
1515 gst_bin_add_many ((GstBin *) ebin, cspace, scale, cspace2, NULL);
1516 tosync = g_list_append (tosync, cspace);
1517 tosync = g_list_append (tosync, scale);
1518 tosync = g_list_append (tosync, cspace2);
1520 sgroup->converters = g_list_prepend (sgroup->converters, cspace);
1521 sgroup->converters = g_list_prepend (sgroup->converters, scale);
1522 sgroup->converters = g_list_prepend (sgroup->converters, cspace2);
1524 if (!fast_element_link (cspace, scale) ||
1525 !fast_element_link (scale, cspace2))
1526 goto converter_link_failure;
1529 if (!gst_encoding_video_profile_get_variableframerate
1530 (GST_ENCODING_VIDEO_PROFILE (sprof))) {
1531 vrate = gst_element_factory_make ("videorate", NULL);
1533 missing_element_name = "videorate";
1534 goto missing_element;
1536 g_object_set (vrate, "skip-to-first", TRUE, NULL);
1538 gst_bin_add ((GstBin *) ebin, vrate);
1539 tosync = g_list_prepend (tosync, vrate);
1540 sgroup->converters = g_list_prepend (sgroup->converters, vrate);
1542 if ((!native_video && !fast_element_link (cspace2, vrate))
1543 || !fast_element_link (vrate, last))
1544 goto converter_link_failure;
1550 } else if (!native_video) {
1551 if (!fast_element_link (cspace2, last))
1552 goto converter_link_failure;
1556 } else if (GST_IS_ENCODING_AUDIO_PROFILE (sprof)
1557 && !(ebin->flags & GST_ENCODEBIN_FLAG_NO_AUDIO_CONVERSION)) {
1558 GstElement *aconv, *ares, *arate, *aconv2;
1560 GST_LOG ("Adding conversion elements for audio stream");
1562 arate = gst_element_factory_make ("audiorate", NULL);
1564 missing_element_name = "audiorate";
1565 goto missing_element;
1567 g_object_set (arate, "tolerance", (guint64) ebin->tolerance, NULL);
1568 g_object_set (arate, "skip-to-first", TRUE, NULL);
1570 aconv = gst_element_factory_make ("audioconvert", NULL);
1571 aconv2 = gst_element_factory_make ("audioconvert", NULL);
1572 ares = gst_element_factory_make ("audioresample", NULL);
1573 if (!aconv || !aconv2) {
1574 missing_element_name = "audioconvert";
1575 goto missing_element;
1578 missing_element_name = "audioresample";
1579 goto missing_element;
1582 gst_bin_add_many ((GstBin *) ebin, arate, aconv, ares, aconv2, NULL);
1583 tosync = g_list_append (tosync, arate);
1584 tosync = g_list_append (tosync, aconv);
1585 tosync = g_list_append (tosync, ares);
1586 tosync = g_list_append (tosync, aconv2);
1587 if (!fast_element_link (arate, aconv) ||
1588 !fast_element_link (aconv, ares) ||
1589 !fast_element_link (ares, aconv2) || !fast_element_link (aconv2, last))
1590 goto converter_link_failure;
1592 sgroup->converters = g_list_prepend (sgroup->converters, arate);
1593 sgroup->converters = g_list_prepend (sgroup->converters, aconv);
1594 sgroup->converters = g_list_prepend (sgroup->converters, ares);
1595 sgroup->converters = g_list_prepend (sgroup->converters, aconv2);
1600 /* Link to stream splitter */
1601 sinkpad = gst_element_get_static_pad (last, "sink");
1603 local_element_request_pad (sgroup->splitter, NULL, "encodingsrc", NULL);
1604 if (G_UNLIKELY (srcpad == NULL))
1605 goto no_splitter_srcpad;
1606 if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1607 goto splitter_encoding_failure;
1608 gst_object_unref (sinkpad);
1609 gst_object_unref (srcpad);
1612 /* End of Stream 2 setup */
1614 /* Sync all elements to parent state */
1615 for (tmp = tosync; tmp; tmp = tmp->next)
1616 gst_element_sync_state_with_parent ((GstElement *) tmp->data);
1617 g_list_free (tosync);
1620 GST_DEBUG ("Adding ghostpad %s:%s", GST_DEBUG_PAD_NAME (sgroup->ghostpad));
1621 gst_pad_set_active (sgroup->ghostpad, TRUE);
1622 gst_element_add_pad ((GstElement *) ebin, sgroup->ghostpad);
1624 /* Add StreamGroup to our list of streams */
1627 ("Done creating elements, adding StreamGroup to our controlled stream list");
1629 ebin->streams = g_list_prepend (ebin->streams, sgroup);
1632 gst_caps_unref (format);
1634 gst_caps_unref (restriction);
1638 splitter_encoding_failure:
1639 GST_ERROR_OBJECT (ebin, "Error linking splitter to encoding stream");
1643 GST_ERROR_OBJECT (ebin,
1644 "Couldn't find a compatible muxer pad to link encoder to");
1648 gst_element_post_message (GST_ELEMENT_CAST (ebin),
1649 gst_missing_element_message_new (GST_ELEMENT_CAST (ebin),
1650 missing_element_name));
1651 GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN,
1652 (_("Missing element '%s' - check your GStreamer installation."),
1653 missing_element_name), (NULL));
1656 encoder_link_failure:
1657 GST_ERROR_OBJECT (ebin, "Failed to link the encoder");
1661 GST_ERROR_OBJECT (ebin, "Couldn't link encoder to muxer");
1664 formatter_link_failure:
1665 GST_ERROR_OBJECT (ebin, "Couldn't link output filter to output queue");
1668 outfilter_link_failure:
1669 GST_ERROR_OBJECT (ebin,
1670 "Couldn't link output filter to output queue/formatter");
1673 passthrough_link_failure:
1674 GST_ERROR_OBJECT (ebin, "Failed linking splitter in passthrough mode");
1678 GST_ERROR_OBJECT (ebin, "Couldn't get a source pad from the splitter");
1681 no_combiner_sinkpad:
1682 GST_ERROR_OBJECT (ebin, "Couldn't get a sink pad from the combiner");
1685 splitter_link_failure:
1686 GST_ERROR_OBJECT (ebin, "Failure linking to the splitter");
1690 GST_ERROR_OBJECT (ebin, "Failure linking to the inqueue");
1693 combiner_link_failure:
1694 GST_ERROR_OBJECT (ebin, "Failure linking to the combiner");
1697 parser_link_failure:
1698 GST_ERROR_OBJECT (ebin, "Failure linking the parser");
1701 converter_link_failure:
1702 GST_ERROR_OBJECT (ebin, "Failure linking the video converters");
1706 /* FIXME : Actually properly cleanup everything */
1708 gst_caps_unref (format);
1710 gst_caps_unref (restriction);
1712 gst_object_unref (srcpad);
1713 stream_group_free (ebin, sgroup);
1714 g_list_free (tosync);
1719 _gst_caps_match_foreach (GQuark field_id, const GValue * value, gpointer data)
1721 GstStructure *structure = data;
1722 const GValue *other_value = gst_structure_id_get_value (structure, field_id);
1724 if (G_UNLIKELY (other_value == NULL))
1726 if (gst_value_compare (value, other_value) == GST_VALUE_EQUAL) {
1734 * checks that there is at least one structure on caps_a that has
1735 * all its fields exactly the same as one structure on caps_b
1738 _gst_caps_match (const GstCaps * caps_a, const GstCaps * caps_b)
1741 gboolean res = FALSE;
1743 for (i = 0; i < gst_caps_get_size (caps_a); i++) {
1744 GstStructure *structure_a = gst_caps_get_structure (caps_a, i);
1745 for (j = 0; j < gst_caps_get_size (caps_b); j++) {
1746 GstStructure *structure_b = gst_caps_get_structure (caps_b, j);
1748 res = gst_structure_foreach (structure_a, _gst_caps_match_foreach,
1759 _factory_can_handle_caps (GstElementFactory * factory, const GstCaps * caps,
1760 GstPadDirection dir, gboolean exact)
1762 const GList *templates;
1764 templates = gst_element_factory_get_static_pad_templates (factory);
1766 GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
1768 if (template->direction == dir) {
1769 GstCaps *tmp = gst_static_caps_get (&template->static_caps);
1771 if ((exact && _gst_caps_match (caps, tmp)) ||
1772 (!exact && gst_caps_can_intersect (tmp, caps))) {
1773 gst_caps_unref (tmp);
1776 gst_caps_unref (tmp);
1778 templates = g_list_next (templates);
1784 static inline GstElement *
1785 _get_formatter (GstEncodeBin * ebin, GstEncodingProfile * sprof)
1787 GList *formatters, *tmpfmtr;
1788 GstElement *formatter = NULL;
1789 GstElementFactory *formatterfact = NULL;
1791 const gchar *preset, *preset_name;
1793 format = gst_encoding_profile_get_format (sprof);
1794 preset = gst_encoding_profile_get_preset (sprof);
1795 preset_name = gst_encoding_profile_get_preset_name (sprof);
1797 GST_DEBUG ("Getting list of formatters for format %" GST_PTR_FORMAT, format);
1800 gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
1803 if (formatters == NULL)
1806 /* FIXME : signal the user if he wants this */
1807 for (tmpfmtr = formatters; tmpfmtr; tmpfmtr = tmpfmtr->next) {
1808 formatterfact = (GstElementFactory *) tmpfmtr->data;
1810 GST_DEBUG_OBJECT (ebin, "Trying formatter %s",
1811 GST_OBJECT_NAME (formatterfact));
1814 _create_element_and_set_preset (formatterfact, preset,
1815 NULL, preset_name)))
1819 gst_plugin_feature_list_free (formatters);
1823 gst_caps_unref (format);
1828 compare_elements (gconstpointer a, gconstpointer b, gpointer udata)
1830 GstCaps *caps = udata;
1831 GstElementFactory *fac_a = (GstElementFactory *) a;
1832 GstElementFactory *fac_b = (GstElementFactory *) b;
1834 /* FIXME not quite sure this is the best algorithm to order the elements
1835 * Some caps similarity comparison algorithm would fit better than going
1836 * boolean (equals/not equals).
1838 gboolean equals_a = _factory_can_handle_caps (fac_a, caps, GST_PAD_SRC, TRUE);
1839 gboolean equals_b = _factory_can_handle_caps (fac_b, caps, GST_PAD_SRC, TRUE);
1841 if (equals_a == equals_b) {
1842 return gst_plugin_feature_get_rank ((GstPluginFeature *) fac_b) -
1843 gst_plugin_feature_get_rank ((GstPluginFeature *) fac_a);
1844 } else if (equals_a) {
1846 } else if (equals_b) {
1852 static inline GstElement *
1853 _get_muxer (GstEncodeBin * ebin)
1855 GList *muxers, *formatters, *tmpmux;
1856 GstElement *muxer = NULL;
1857 GstElementFactory *muxerfact = NULL;
1860 const gchar *preset, *preset_name;
1862 format = gst_encoding_profile_get_format (ebin->profile);
1863 preset = gst_encoding_profile_get_preset (ebin->profile);
1864 preset_name = gst_encoding_profile_get_preset_name (ebin->profile);
1866 GST_DEBUG ("Getting list of muxers for format %" GST_PTR_FORMAT, format);
1869 gst_element_factory_list_filter (ebin->muxers, format, GST_PAD_SRC, TRUE);
1872 gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
1875 muxers = g_list_sort_with_data (muxers, compare_elements, (gpointer) format);
1877 g_list_sort_with_data (formatters, compare_elements, (gpointer) format);
1879 muxers = g_list_concat (muxers, formatters);
1884 /* FIXME : signal the user if he wants this */
1885 for (tmpmux = muxers; tmpmux; tmpmux = tmpmux->next) {
1886 gboolean cansinkstreams = TRUE;
1887 const GList *profiles =
1888 gst_encoding_container_profile_get_profiles
1889 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
1891 muxerfact = (GstElementFactory *) tmpmux->data;
1893 GST_DEBUG ("Trying muxer %s", GST_OBJECT_NAME (muxerfact));
1895 /* See if the muxer can sink all of our stream profile caps */
1896 for (tmp = profiles; tmp; tmp = tmp->next) {
1897 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
1898 GstCaps *sformat = gst_encoding_profile_get_format (sprof);
1900 if (!_factory_can_handle_caps (muxerfact, sformat, GST_PAD_SINK, FALSE)) {
1901 GST_DEBUG ("Skipping muxer because it can't sink caps %"
1902 GST_PTR_FORMAT, sformat);
1903 cansinkstreams = FALSE;
1905 gst_caps_unref (sformat);
1909 gst_caps_unref (sformat);
1912 /* Only use a muxer than can use all streams and than can accept the
1913 * preset (which may be present or not) */
1914 if (cansinkstreams && (muxer =
1915 _create_element_and_set_preset (muxerfact, preset, "muxer",
1920 gst_plugin_feature_list_free (muxers);
1924 gst_caps_unref (format);
1929 create_elements_and_pads (GstEncodeBin * ebin)
1931 gboolean ret = TRUE;
1932 GstElement *muxer = NULL;
1934 const GList *tmp, *profiles;
1935 GstEncodingProfile *sprof;
1937 GST_DEBUG ("Current profile : %s",
1938 gst_encoding_profile_get_name (ebin->profile));
1940 if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
1941 /* 1. Get the compatible muxer */
1942 muxer = _get_muxer (ebin);
1943 if (G_UNLIKELY (muxer == NULL))
1946 /* Record the muxer */
1947 ebin->muxer = muxer;
1948 gst_bin_add ((GstBin *) ebin, muxer);
1950 /* 2. Ghost the muxer source pad */
1952 /* FIXME : We should figure out if it's a static/request/dyamic pad,
1953 * but for the time being let's assume it's a static pad :) */
1954 muxerpad = gst_element_get_static_pad (muxer, "src");
1955 if (G_UNLIKELY (muxerpad == NULL))
1958 if (!gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), muxerpad))
1959 goto no_muxer_ghost_pad;
1961 gst_object_unref (muxerpad);
1962 /* 3. Activate fixed presence streams */
1964 gst_encoding_container_profile_get_profiles
1965 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
1966 for (tmp = profiles; tmp; tmp = tmp->next) {
1967 sprof = (GstEncodingProfile *) tmp->data;
1969 GST_DEBUG ("Trying stream profile with presence %d",
1970 gst_encoding_profile_get_presence (sprof));
1972 if (gst_encoding_profile_get_presence (sprof) != 0 &&
1973 gst_encoding_profile_is_enabled (sprof)) {
1974 if (G_UNLIKELY (_create_stream_group (ebin, sprof, NULL, NULL,
1979 gst_element_sync_state_with_parent (muxer);
1981 if (G_UNLIKELY (_create_stream_group (ebin, ebin->profile, NULL,
1982 NULL, NULL) == NULL))
1990 GstCaps *format = gst_encoding_profile_get_format (ebin->profile);
1992 GST_WARNING ("No available muxer for %" GST_PTR_FORMAT, format);
1993 /* missing plugin support */
1994 gst_element_post_message (GST_ELEMENT_CAST (ebin),
1995 gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format));
1996 GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN,
1997 ("No available muxer for format %" GST_PTR_FORMAT, format), (NULL));
1999 gst_caps_unref (format);
2005 GST_WARNING ("Can't get source pad from muxer (%s)",
2006 GST_ELEMENT_NAME (muxer));
2007 gst_bin_remove (GST_BIN (ebin), muxer);
2013 GST_WARNING ("Couldn't set %s:%s as source ghostpad target",
2014 GST_DEBUG_PAD_NAME (muxerpad));
2015 gst_bin_remove (GST_BIN (ebin), muxer);
2016 gst_object_unref (muxerpad);
2022 GST_WARNING ("Could not create Streams");
2024 gst_bin_remove (GST_BIN (ebin), muxer);
2031 release_pads (const GValue * item, GstElement * elt)
2033 GstPad *pad = g_value_get_object (item);
2034 GstPad *peer = NULL;
2036 GST_DEBUG_OBJECT (elt, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
2038 /* Unlink from its peer pad */
2039 if ((peer = gst_pad_get_peer (pad))) {
2040 if (GST_PAD_DIRECTION (peer) == GST_PAD_SRC)
2041 gst_pad_unlink (peer, pad);
2043 gst_pad_unlink (pad, peer);
2044 gst_object_unref (peer);
2047 /* Release it from the object */
2048 gst_element_release_request_pad (elt, pad);
2052 stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup)
2058 GST_DEBUG_OBJECT (ebin, "Freeing StreamGroup %p", sgroup);
2060 if (sgroup->restriction_sid != 0)
2061 g_signal_handler_disconnect (sgroup->profile, sgroup->restriction_sid);
2063 if (sgroup->outqueue) {
2065 /* outqueue - Muxer */
2066 tmppad = gst_element_get_static_pad (sgroup->outqueue, "src");
2067 pad = gst_pad_get_peer (tmppad);
2070 /* Remove muxer request sink pad */
2071 gst_pad_unlink (tmppad, pad);
2072 if (GST_PAD_TEMPLATE_PRESENCE (GST_PAD_PAD_TEMPLATE (pad)) ==
2074 gst_element_release_request_pad (ebin->muxer, pad);
2075 gst_object_unref (pad);
2077 gst_object_unref (tmppad);
2079 gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
2082 if (sgroup->formatter) {
2083 /* capsfilter - formatter - outqueue */
2084 gst_element_set_state (sgroup->formatter, GST_STATE_NULL);
2085 gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
2086 gst_element_unlink (sgroup->formatter, sgroup->outqueue);
2087 gst_element_unlink (sgroup->outfilter, sgroup->formatter);
2088 } else if (sgroup->outfilter) {
2089 /* Capsfilter - outqueue */
2090 gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
2091 gst_element_unlink (sgroup->outfilter, sgroup->outqueue);
2094 if (sgroup->outqueue) {
2095 gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
2096 gst_bin_remove (GST_BIN (ebin), sgroup->outqueue);
2099 /* streamcombiner - parser - capsfilter */
2100 if (sgroup->parser) {
2101 gst_element_set_state (sgroup->parser, GST_STATE_NULL);
2102 gst_element_unlink (sgroup->parser, sgroup->outfilter);
2103 gst_element_unlink (sgroup->combiner, sgroup->parser);
2104 gst_bin_remove ((GstBin *) ebin, sgroup->parser);
2108 if (sgroup->ghostpad) {
2109 if (GST_PAD_PARENT (sgroup->ghostpad) != NULL)
2110 gst_element_remove_pad (GST_ELEMENT_CAST (ebin), sgroup->ghostpad);
2112 gst_object_unref (sgroup->ghostpad);
2115 if (sgroup->inqueue)
2116 gst_element_set_state (sgroup->inqueue, GST_STATE_NULL);
2118 if (sgroup->encoder)
2119 gst_element_set_state (sgroup->encoder, GST_STATE_NULL);
2120 if (sgroup->fakesink)
2121 gst_element_set_state (sgroup->fakesink, GST_STATE_NULL);
2122 if (sgroup->outfilter) {
2123 gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
2125 if (sgroup->outputfilter_caps_sid) {
2126 g_signal_handler_disconnect (sgroup->outfilter->sinkpads->data,
2127 sgroup->outputfilter_caps_sid);
2128 sgroup->outputfilter_caps_sid = 0;
2131 if (sgroup->smartencoder)
2132 gst_element_set_state (sgroup->smartencoder, GST_STATE_NULL);
2134 if (sgroup->capsfilter) {
2135 gst_element_set_state (sgroup->capsfilter, GST_STATE_NULL);
2136 if (sgroup->encoder)
2137 gst_element_unlink (sgroup->capsfilter, sgroup->encoder);
2139 gst_element_unlink (sgroup->capsfilter, sgroup->fakesink);
2141 if (sgroup->inputfilter_caps_sid) {
2142 g_signal_handler_disconnect (sgroup->capsfilter->sinkpads->data,
2143 sgroup->inputfilter_caps_sid);
2144 sgroup->inputfilter_caps_sid = 0;
2146 gst_bin_remove ((GstBin *) ebin, sgroup->capsfilter);
2149 for (tmp = sgroup->converters; tmp; tmp = tmp->next) {
2150 GstElement *elt = (GstElement *) tmp->data;
2152 gst_element_set_state (elt, GST_STATE_NULL);
2153 gst_bin_remove ((GstBin *) ebin, elt);
2155 if (sgroup->converters)
2156 g_list_free (sgroup->converters);
2158 if (sgroup->combiner) {
2159 GstIterator *it = gst_element_iterate_sink_pads (sgroup->combiner);
2160 GstIteratorResult itret = GST_ITERATOR_OK;
2162 while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
2164 gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
2166 gst_iterator_resync (it);
2168 gst_iterator_free (it);
2169 gst_element_set_state (sgroup->combiner, GST_STATE_NULL);
2170 gst_bin_remove ((GstBin *) ebin, sgroup->combiner);
2173 if (sgroup->splitter) {
2174 GstIterator *it = gst_element_iterate_src_pads (sgroup->splitter);
2175 GstIteratorResult itret = GST_ITERATOR_OK;
2176 while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
2178 gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
2180 gst_iterator_resync (it);
2182 gst_iterator_free (it);
2184 gst_element_set_state (sgroup->splitter, GST_STATE_NULL);
2185 gst_bin_remove ((GstBin *) ebin, sgroup->splitter);
2188 if (sgroup->inqueue)
2189 gst_bin_remove ((GstBin *) ebin, sgroup->inqueue);
2191 if (sgroup->encoder)
2192 gst_bin_remove ((GstBin *) ebin, sgroup->encoder);
2194 if (sgroup->fakesink)
2195 gst_bin_remove ((GstBin *) ebin, sgroup->fakesink);
2197 if (sgroup->smartencoder)
2198 gst_bin_remove ((GstBin *) ebin, sgroup->smartencoder);
2200 if (sgroup->outfilter)
2201 gst_bin_remove ((GstBin *) ebin, sgroup->outfilter);
2203 g_slice_free (StreamGroup, sgroup);
2207 stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup)
2209 ebin->streams = g_list_remove (ebin->streams, sgroup);
2211 stream_group_free (ebin, sgroup);
2215 gst_encode_bin_tear_down_profile (GstEncodeBin * ebin)
2217 if (G_UNLIKELY (ebin->profile == NULL))
2220 GST_DEBUG ("Tearing down profile %s",
2221 gst_encoding_profile_get_name (ebin->profile));
2223 while (ebin->streams)
2224 stream_group_remove (ebin, (StreamGroup *) ebin->streams->data);
2226 /* Set ghostpad target to NULL */
2227 gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), NULL);
2229 /* Remove muxer if present */
2231 gst_element_set_state (ebin->muxer, GST_STATE_NULL);
2232 gst_bin_remove (GST_BIN (ebin), ebin->muxer);
2236 /* free/clear profile */
2237 gst_encoding_profile_unref (ebin->profile);
2238 ebin->profile = NULL;
2242 gst_encode_bin_setup_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
2246 g_return_val_if_fail (ebin->profile == NULL, FALSE);
2248 GST_DEBUG ("Setting up profile %p:%s (type:%s)", profile,
2249 gst_encoding_profile_get_name (profile),
2250 gst_encoding_profile_get_type_nick (profile));
2252 ebin->profile = profile;
2253 gst_object_ref (ebin->profile);
2255 /* Create elements */
2256 res = create_elements_and_pads (ebin);
2258 gst_encode_bin_tear_down_profile (ebin);
2264 gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
2266 g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
2268 GST_DEBUG_OBJECT (ebin, "profile (%p) : %s", profile,
2269 gst_encoding_profile_get_name (profile));
2271 if (G_UNLIKELY (ebin->active)) {
2272 GST_WARNING_OBJECT (ebin, "Element already active, can't change profile");
2276 /* If we're not active, we can deactivate the previous profile */
2277 if (ebin->profile) {
2278 gst_encode_bin_tear_down_profile (ebin);
2281 return gst_encode_bin_setup_profile (ebin, profile);
2284 static inline gboolean
2285 gst_encode_bin_activate (GstEncodeBin * ebin)
2287 ebin->active = ebin->profile != NULL;
2288 return ebin->active;
2292 gst_encode_bin_deactivate (GstEncodeBin * ebin)
2296 for (tmp = ebin->streams; tmp; tmp = tmp->next) {
2297 StreamGroup *sgroup = tmp->data;
2298 GstCaps *format = gst_encoding_profile_get_format (sgroup->profile);
2300 _set_group_caps_format (sgroup, sgroup->profile, format);
2303 gst_caps_unref (format);
2306 ebin->active = FALSE;
2309 static GstStateChangeReturn
2310 gst_encode_bin_change_state (GstElement * element, GstStateChange transition)
2312 GstStateChangeReturn ret;
2313 GstEncodeBin *ebin = (GstEncodeBin *) element;
2315 switch (transition) {
2316 case GST_STATE_CHANGE_READY_TO_PAUSED:
2317 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2318 if (!gst_encode_bin_activate (ebin)) {
2319 ret = GST_STATE_CHANGE_FAILURE;
2328 GST_ELEMENT_CLASS (gst_encode_bin_parent_class)->change_state (element,
2330 if (ret == GST_STATE_CHANGE_FAILURE)
2333 switch (transition) {
2334 case GST_STATE_CHANGE_PAUSED_TO_READY:
2335 gst_encode_bin_deactivate (ebin);
2347 plugin_init (GstPlugin * plugin)
2351 GST_DEBUG_CATEGORY_INIT (gst_encode_bin_debug, "encodebin", 0, "encoder bin");
2354 GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
2356 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
2357 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2358 #endif /* ENABLE_NLS */
2361 res = gst_element_register (plugin, "encodebin", GST_RANK_NONE,
2362 GST_TYPE_ENCODE_BIN);
2367 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2370 "various encoding-related elements", plugin_init, VERSION, GST_LICENSE,
2371 GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)