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., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, 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
35 * EncodeBin provides a bin for encoding/muxing various streams according to
36 * a specified #GstEncodingProfile.
38 * Based on the profile that was set (via the #GstEncodeBin:profile property),
39 * EncodeBin will internally select and configure the required elements
40 * (encoders, muxers, but also audio and video converters) so that you can
41 * provide it raw or pre-encoded streams of data in input and have your
42 * encoded/muxed/converted stream in output.
45 * <title>Features</title>
48 * Automatic encoder and muxer selection based on elements available on the
52 * Conversion of raw audio/video streams (scaling, framerate conversion,
53 * colorspace conversion, samplerate conversion) to conform to the profile
57 * Variable number of streams. If the presence property for a stream encoding
58 * profile is 0, you can request any number of sink pads for it via the
59 * standard request pad gstreamer API or the #GstEncodeBin::request-pad action
63 * Avoid reencoding (passthrough). If the input stream is already encoded and is
64 * compatible with what the #GstEncodingProfile expects, then the stream won't
65 * be re-encoded but just passed through downstream to the muxer or the output.
68 * Mix pre-encoded and raw streams as input. In addition to the passthrough
69 * feature above, you can feed both raw audio/video *AND* already-encoded data
70 * to a pad. #GstEncodeBin will take care of passing through the compatible
71 * segments and re-encoding the segments of media that need encoding.
74 * Standard behaviour is to use a #GstEncodingContainerProfile to have both
75 * encoding and muxing performed. But you can also provide a single stream
76 * profile (like #GstEncodingAudioProfile) to only have the encoding done and
77 * handle the encoded output yourself.
80 * Audio imperfection corrections. Incoming audio streams can have non perfect
81 * timestamps (jitter), like the streams coming from ASF files. #GstEncodeBin
82 * will automatically fix those imperfections for you. See
83 * #GstEncodeBin:audio-jitter-tolerance for more details.
86 * Variable or Constant video framerate. If your #GstEncodingVideoProfile has
87 * the variableframerate property deactivated (default), then the incoming
88 * raw video stream will be retimestampped in order to produce a constant
92 * Cross-boundary re-encoding. When feeding compatible pre-encoded streams that
93 * fall on segment boundaries, and for supported formats (right now only H263),
94 * the GOP will be decoded/reencoded when needed to produce an encoded output
95 * that fits exactly within the request GstSegment.
98 * Missing plugin support. If a #GstElement is missing to encode/mux to the
99 * request profile formats, a missing-plugin #GstMessage will be posted on the
100 * #GstBus, allowing systems that support the missing-plugin system to offer the
101 * user a way to install the missing element.
110 * Handling mp3!xing!idv3 and theora!ogg tagsetting scenarios:
111 * Once we have chosen a muxer:
112 * When a new stream is requested:
113 * If muxer is 'Formatter' OR doesn't have a TagSetter interface:
114 * Find a Formatter for the given stream (preferably with TagSetter)
115 * Insert that before muxer
118 #define fast_pad_link(a,b) gst_pad_link_full((a),(b),GST_PAD_LINK_CHECK_NOTHING)
119 #define fast_element_link(a,b) gst_element_link_pads_full((a),"src",(b),"sink",GST_PAD_LINK_CHECK_NOTHING)
121 /* generic templates */
122 static GstStaticPadTemplate muxer_src_template =
123 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
124 GST_STATIC_CAPS_ANY);
126 static GstStaticPadTemplate video_sink_template =
127 GST_STATIC_PAD_TEMPLATE ("video_%d",
130 GST_STATIC_CAPS_ANY);
131 static GstStaticPadTemplate audio_sink_template =
132 GST_STATIC_PAD_TEMPLATE ("audio_%d",
135 GST_STATIC_CAPS_ANY);
136 /* static GstStaticPadTemplate text_sink_template = */
137 /* GST_STATIC_PAD_TEMPLATE ("text_%d", */
139 /* GST_PAD_REQUEST, */
140 /* GST_STATIC_CAPS_ANY); */
141 static GstStaticPadTemplate private_sink_template =
142 GST_STATIC_PAD_TEMPLATE ("private_%d",
145 GST_STATIC_CAPS_ANY);
151 /* the profile field is only valid if it could be entirely setup */
152 GstEncodingProfile *profile;
154 GList *streams; /* List of StreamGroup, not sorted */
157 /* Ghostpad with changing target */
160 /* TRUE if in PAUSED/PLAYING */
163 /* available muxers, encoders and parsers */
168 /* Increasing counter for unique pad name */
171 /* Cached caps for identification */
172 GstCaps *raw_video_caps;
173 GstCaps *raw_audio_caps;
174 /* GstCaps *raw_text_caps; */
176 guint queue_buffers_max;
177 guint queue_bytes_max;
178 guint64 queue_time_max;
181 gboolean avoid_reencoding;
184 struct _GstEncodeBinClass
189 GstPad *(*request_pad) (GstEncodeBin * encodebin, GstCaps * caps);
192 typedef struct _StreamGroup StreamGroup;
197 GstEncodingProfile *profile;
198 GstPad *ghostpad; /* Sink ghostpad */
199 GstElement *inqueue; /* Queue just after the ghostpad */
200 GstElement *splitter;
201 GList *converters; /* List of conversion GstElement */
202 GstElement *capsfilter; /* profile->restriction (if non-NULL/ANY) */
203 GstElement *encoder; /* Encoder (can be NULL) */
204 GstElement *combiner;
206 GstElement *smartencoder;
207 GstElement *outfilter; /* Output capsfilter (streamprofile.format) */
208 GstElement *outqueue; /* Queue just before the muxer */
211 /* Default for queues (same defaults as queue element) */
212 #define DEFAULT_QUEUE_BUFFERS_MAX 200
213 #define DEFAULT_QUEUE_BYTES_MAX 10 * 1024 * 1024
214 #define DEFAULT_QUEUE_TIME_MAX GST_SECOND
215 #define DEFAULT_AUDIO_JITTER_TOLERANCE 20 * GST_MSECOND
216 #define DEFAULT_AVOID_REENCODING FALSE
218 #define DEFAULT_RAW_CAPS \
219 "video/x-raw-yuv; " \
220 "video/x-raw-rgb; " \
221 "video/x-raw-gray; " \
222 "audio/x-raw-int; " \
223 "audio/x-raw-float; " \
225 "text/x-pango-markup; " \
226 "video/x-dvd-subpicture; " \
234 PROP_QUEUE_BUFFERS_MAX,
235 PROP_QUEUE_BYTES_MAX,
237 PROP_AUDIO_JITTER_TOLERANCE,
238 PROP_AVOID_REENCODING,
249 static guint gst_encode_bin_signals[LAST_SIGNAL] = { 0 };
251 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
253 GST_DEBUG_CATEGORY_STATIC (gst_encode_bin_debug);
254 #define GST_CAT_DEFAULT gst_encode_bin_debug
256 G_DEFINE_TYPE (GstEncodeBin, gst_encode_bin, GST_TYPE_BIN);
258 static void gst_encode_bin_dispose (GObject * object);
259 static void gst_encode_bin_set_property (GObject * object, guint prop_id,
260 const GValue * value, GParamSpec * pspec);
261 static void gst_encode_bin_get_property (GObject * object, guint prop_id,
262 GValue * value, GParamSpec * pspec);
263 static GstStateChangeReturn gst_encode_bin_change_state (GstElement * element,
264 GstStateChange transition);
266 static GstPad *gst_encode_bin_request_new_pad (GstElement * element,
267 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
268 static void gst_encode_bin_release_pad (GstElement * element, GstPad * pad);
271 gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile);
272 static void gst_encode_bin_tear_down_profile (GstEncodeBin * ebin);
273 static gboolean gst_encode_bin_setup_profile (GstEncodeBin * ebin,
274 GstEncodingProfile * profile);
276 static StreamGroup *_create_stream_group (GstEncodeBin * ebin,
277 GstEncodingProfile * sprof, const gchar * sinkpadname, GstCaps * sinkcaps);
278 static void stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup);
279 static GstPad *gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin,
283 gst_encode_bin_class_init (GstEncodeBinClass * klass)
285 GObjectClass *gobject_klass;
286 GstElementClass *gstelement_klass;
288 gobject_klass = (GObjectClass *) klass;
289 gstelement_klass = (GstElementClass *) klass;
291 gobject_klass->dispose = gst_encode_bin_dispose;
292 gobject_klass->set_property = gst_encode_bin_set_property;
293 gobject_klass->get_property = gst_encode_bin_get_property;
298 * GstEncodeBin:profile:
300 * The #GstEncodingProfile to use. This property must be set before going
301 * to %GST_STATE_PAUSED or higher.
303 g_object_class_install_property (gobject_klass, PROP_PROFILE,
304 gst_param_spec_mini_object ("profile", "Profile",
305 "The GstEncodingProfile to use", GST_TYPE_ENCODING_PROFILE,
306 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
308 g_object_class_install_property (gobject_klass, PROP_QUEUE_BUFFERS_MAX,
309 g_param_spec_uint ("queue-bytes-max", "Max. size (kB)",
310 "Max. amount of data in the queue (bytes, 0=disable)",
311 0, G_MAXUINT, DEFAULT_QUEUE_BYTES_MAX,
312 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
314 g_object_class_install_property (gobject_klass, PROP_QUEUE_BYTES_MAX,
315 g_param_spec_uint ("queue-buffers-max", "Max. size (buffers)",
316 "Max. number of buffers in the queue (0=disable)", 0, G_MAXUINT,
317 DEFAULT_QUEUE_BUFFERS_MAX,
318 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
320 g_object_class_install_property (gobject_klass, PROP_QUEUE_TIME_MAX,
321 g_param_spec_uint64 ("queue-time-max", "Max. size (ns)",
322 "Max. amount of data in the queue (in ns, 0=disable)", 0, G_MAXUINT64,
323 DEFAULT_QUEUE_TIME_MAX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
325 g_object_class_install_property (gobject_klass, PROP_AUDIO_JITTER_TOLERANCE,
326 g_param_spec_uint64 ("audio-jitter-tolerance", "Audio jitter tolerance",
327 "Amount of timestamp jitter/imperfection to allow on audio streams before inserting/dropping samples (ns)",
328 0, G_MAXUINT64, DEFAULT_AUDIO_JITTER_TOLERANCE,
329 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
331 g_object_class_install_property (gobject_klass, PROP_AVOID_REENCODING,
332 g_param_spec_boolean ("avoid-reencoding", "Avoid re-encoding",
333 "Whether to re-encode portions of compatible video streams that lay on segment boundaries",
334 DEFAULT_AVOID_REENCODING,
335 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
339 * GstEncodeBin::request-pad
340 * @encodebin: a #GstEncodeBin instance
343 * Use this method to request an unused sink request #GstPad that can take the
344 * provided @caps as input. You must release the pad with
345 * gst_element_release_request_pad() when you are done with it.
347 * Returns: A compatible #GstPad, or %NULL if no compatible #GstPad could be
348 * created or is available.
350 gst_encode_bin_signals[SIGNAL_REQUEST_PAD] =
351 g_signal_new ("request-pad", G_TYPE_FROM_CLASS (klass),
352 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstEncodeBinClass,
353 request_pad), NULL, NULL, gst_encode_marshal_OBJECT__BOXED,
354 GST_TYPE_PAD, 1, GST_TYPE_CAPS);
356 klass->request_pad = gst_encode_bin_request_pad_signal;
358 gst_element_class_add_pad_template (gstelement_klass,
359 gst_static_pad_template_get (&muxer_src_template));
360 gst_element_class_add_pad_template (gstelement_klass,
361 gst_static_pad_template_get (&video_sink_template));
362 gst_element_class_add_pad_template (gstelement_klass,
363 gst_static_pad_template_get (&audio_sink_template));
364 /* gst_element_class_add_pad_template (gstelement_klass, */
365 /* gst_static_pad_template_get (&text_sink_template)); */
366 gst_element_class_add_pad_template (gstelement_klass,
367 gst_static_pad_template_get (&private_sink_template));
369 gstelement_klass->change_state =
370 GST_DEBUG_FUNCPTR (gst_encode_bin_change_state);
371 gstelement_klass->request_new_pad_full =
372 GST_DEBUG_FUNCPTR (gst_encode_bin_request_new_pad);
373 gstelement_klass->release_pad =
374 GST_DEBUG_FUNCPTR (gst_encode_bin_release_pad);
376 gst_element_class_set_details_simple (gstelement_klass,
378 "Generic/Bin/Encoder",
379 "Convenience encoding/muxing element",
380 "Edward Hervey <edward.hervey@collabora.co.uk>");
384 gst_encode_bin_dispose (GObject * object)
386 GstEncodeBin *ebin = (GstEncodeBin *) object;
389 gst_plugin_feature_list_free (ebin->muxers);
392 gst_plugin_feature_list_free (ebin->encoders);
395 gst_plugin_feature_list_free (ebin->parsers);
397 gst_encode_bin_tear_down_profile (ebin);
399 if (ebin->raw_video_caps)
400 gst_caps_unref (ebin->raw_video_caps);
401 if (ebin->raw_audio_caps)
402 gst_caps_unref (ebin->raw_audio_caps);
403 /* if (ebin->raw_text_caps) */
404 /* gst_caps_unref (ebin->raw_text_caps); */
406 G_OBJECT_CLASS (gst_encode_bin_parent_class)->dispose (object);
410 gst_encode_bin_init (GstEncodeBin * encode_bin)
412 GstPadTemplate *tmpl;
416 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER,
419 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_FORMATTER,
421 encode_bin->muxers = g_list_concat (encode_bin->muxers, formatters);
423 encode_bin->encoders =
424 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER,
427 encode_bin->parsers =
428 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER,
431 encode_bin->raw_video_caps =
432 gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb;video/x-raw-gray");
433 encode_bin->raw_audio_caps =
434 gst_caps_from_string ("audio/x-raw-int;audio/x-raw-float");
435 /* encode_bin->raw_text_caps = */
436 /* gst_caps_from_string ("text/plain;text/x-pango-markup"); */
438 encode_bin->queue_buffers_max = DEFAULT_QUEUE_BUFFERS_MAX;
439 encode_bin->queue_bytes_max = DEFAULT_QUEUE_BYTES_MAX;
440 encode_bin->queue_time_max = DEFAULT_QUEUE_TIME_MAX;
441 encode_bin->tolerance = DEFAULT_AUDIO_JITTER_TOLERANCE;
442 encode_bin->avoid_reencoding = DEFAULT_AVOID_REENCODING;
444 tmpl = gst_static_pad_template_get (&muxer_src_template);
445 encode_bin->srcpad = gst_ghost_pad_new_no_target_from_template ("src", tmpl);
446 gst_object_unref (tmpl);
447 gst_element_add_pad (GST_ELEMENT_CAST (encode_bin), encode_bin->srcpad);
451 gst_encode_bin_set_property (GObject * object, guint prop_id,
452 const GValue * value, GParamSpec * pspec)
454 GstEncodeBin *ebin = (GstEncodeBin *) object;
458 gst_encode_bin_set_profile (ebin,
459 (GstEncodingProfile *) gst_value_get_mini_object (value));
461 case PROP_QUEUE_BUFFERS_MAX:
462 ebin->queue_buffers_max = g_value_get_uint (value);
464 case PROP_QUEUE_BYTES_MAX:
465 ebin->queue_bytes_max = g_value_get_uint (value);
467 case PROP_QUEUE_TIME_MAX:
468 ebin->queue_time_max = g_value_get_uint64 (value);
470 case PROP_AUDIO_JITTER_TOLERANCE:
471 ebin->tolerance = g_value_get_uint64 (value);
473 case PROP_AVOID_REENCODING:
474 ebin->avoid_reencoding = g_value_get_boolean (value);
477 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
483 gst_encode_bin_get_property (GObject * object, guint prop_id,
484 GValue * value, GParamSpec * pspec)
486 GstEncodeBin *ebin = (GstEncodeBin *) object;
490 gst_value_set_mini_object (value, (GstMiniObject *) ebin->profile);
492 case PROP_QUEUE_BUFFERS_MAX:
493 g_value_set_uint (value, ebin->queue_buffers_max);
495 case PROP_QUEUE_BYTES_MAX:
496 g_value_set_uint (value, ebin->queue_bytes_max);
498 case PROP_QUEUE_TIME_MAX:
499 g_value_set_uint64 (value, ebin->queue_time_max);
501 case PROP_AUDIO_JITTER_TOLERANCE:
502 g_value_set_uint64 (value, ebin->tolerance);
504 case PROP_AVOID_REENCODING:
505 g_value_set_boolean (value, ebin->avoid_reencoding);
508 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
513 static inline gboolean
514 are_raw_caps (const GstCaps * caps)
516 GstCaps *raw = gst_static_caps_get (&default_raw_caps);
518 if (gst_caps_can_intersect (caps, raw)) {
519 gst_caps_unref (raw);
522 gst_caps_unref (raw);
526 /* Returns the number of time a given stream profile is currently used
529 stream_profile_used_count (GstEncodeBin * ebin, GstEncodingProfile * sprof)
531 guint nbprofused = 0;
534 for (tmp = ebin->streams; tmp; tmp = tmp->next) {
535 StreamGroup *sgroup = (StreamGroup *) tmp->data;
537 if (sgroup->profile == sprof)
544 static inline GstEncodingProfile *
545 next_unused_stream_profile (GstEncodeBin * ebin, GType ptype, GstCaps * caps)
547 GST_DEBUG_OBJECT (ebin, "ptype:%s, caps:%" GST_PTR_FORMAT,
548 g_type_name (ptype), caps);
550 if (G_UNLIKELY (ptype == G_TYPE_NONE && caps != NULL)) {
551 /* Identify the profile type based on raw caps */
552 if (gst_caps_can_intersect (ebin->raw_video_caps, caps))
553 ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
554 else if (gst_caps_can_intersect (ebin->raw_audio_caps, caps))
555 ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
556 /* else if (gst_caps_can_intersect (ebin->raw_text_caps, caps)) */
557 /* ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
558 GST_DEBUG_OBJECT (ebin, "Detected profile type as being %s",
559 g_type_name (ptype));
562 if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
566 gst_encoding_container_profile_get_profiles
567 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile)); tmp;
569 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
571 /* Pick an available Stream profile for which:
572 * * either it is of the compatibly raw type,
573 * * OR we can pass it through directly without encoding
575 if (G_TYPE_FROM_INSTANCE (sprof) == ptype) {
576 guint presence = gst_encoding_profile_get_presence (sprof);
577 GST_DEBUG ("Found a stream profile with the same type");
579 || (presence > stream_profile_used_count (ebin, sprof)))
581 } else if ((caps != NULL) && (ptype == G_TYPE_NONE)) {
585 outcaps = gst_encoding_profile_get_input_caps (sprof);
586 GST_DEBUG ("Unknown stream, seeing if it's compatible with %"
587 GST_PTR_FORMAT, outcaps);
588 res = gst_caps_can_intersect (outcaps, caps);
589 gst_caps_unref (outcaps);
601 request_pad_for_stream (GstEncodeBin * encodebin, GType ptype,
602 const gchar * name, GstCaps * caps)
605 GstEncodingProfile *sprof;
607 GST_DEBUG_OBJECT (encodebin, "name:%s caps:%" GST_PTR_FORMAT, name, caps);
609 /* Figure out if we have a unused GstEncodingProfile we can use for
611 sprof = next_unused_stream_profile (encodebin, ptype, caps);
613 if (G_UNLIKELY (sprof == NULL))
614 goto no_stream_profile;
616 sgroup = _create_stream_group (encodebin, sprof, name, caps);
617 if (G_UNLIKELY (sgroup == NULL))
618 goto no_stream_group;
620 return sgroup->ghostpad;
624 GST_WARNING_OBJECT (encodebin, "Couldn't find a compatible stream profile");
630 GST_WARNING_OBJECT (encodebin, "Couldn't create a StreamGroup");
636 gst_encode_bin_request_new_pad (GstElement * element,
637 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
639 GstEncodeBin *ebin = (GstEncodeBin *) element;
642 GST_DEBUG_OBJECT (element, "templ:%s, name:%s", templ->name_template, name);
644 /* Identify the stream group */
646 res = request_pad_for_stream (ebin, G_TYPE_NONE, name, (GstCaps *) caps);
650 GType ptype = G_TYPE_NONE;
652 if (!strcmp (templ->name_template, "video_%d"))
653 ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
654 else if (!strcmp (templ->name_template, "audio_%d"))
655 ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
656 /* else if (!strcmp (templ->name_template, "text_%d")) */
657 /* ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
659 /* FIXME : Check uniqueness of pad */
660 /* FIXME : Check that the requested number is the last one, and if not,
661 * update the last_pad_id variable so that we don't create a pad with
662 * the same name/number in the future */
664 res = request_pad_for_stream (ebin, ptype, name, NULL);
671 gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin, GstCaps * caps)
673 GstPad *pad = request_pad_for_stream (encodebin, G_TYPE_NONE, NULL, caps);
675 return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL;
678 static inline StreamGroup *
679 find_stream_group_from_pad (GstEncodeBin * ebin, GstPad * pad)
683 for (tmp = ebin->streams; tmp; tmp = tmp->next) {
684 StreamGroup *sgroup = (StreamGroup *) tmp->data;
685 if (G_UNLIKELY (sgroup->ghostpad == pad))
693 gst_encode_bin_release_pad (GstElement * element, GstPad * pad)
695 GstEncodeBin *ebin = (GstEncodeBin *) element;
698 /* Find the associated StreamGroup */
700 sgroup = find_stream_group_from_pad (ebin, pad);
701 if (G_UNLIKELY (sgroup == NULL))
702 goto no_stream_group;
704 /* Release objects/data associated with the StreamGroup */
705 stream_group_remove (ebin, sgroup);
711 GST_WARNING_OBJECT (ebin, "Couldn't find corresponding StreamGroup");
716 /* Create a parser for the given stream profile */
717 static inline GstElement *
718 _get_parser (GstEncodeBin * ebin, GstEncodingProfile * sprof)
720 GList *parsers1, *parsers, *tmp;
721 GstElement *parser = NULL;
722 GstElementFactory *parserfact = NULL;
723 const GstCaps *format;
725 format = gst_encoding_profile_get_format (sprof);
727 GST_DEBUG ("Getting list of parsers for format %" GST_PTR_FORMAT, format);
729 /* FIXME : requesting twice the parsers twice is a bit ugly, we should
730 * have a method to request on more than one condition */
732 gst_element_factory_list_filter (ebin->parsers, format,
735 gst_element_factory_list_filter (parsers1, format, GST_PAD_SINK, FALSE);
736 gst_plugin_feature_list_free (parsers1);
738 if (G_UNLIKELY (parsers == NULL)) {
739 GST_DEBUG ("Couldn't find any compatible parsers");
743 for (tmp = parsers; tmp; tmp = tmp->next) {
744 /* FIXME : We're only picking the first one so far */
745 /* FIXME : signal the user if he wants this */
746 parserfact = (GstElementFactory *) tmp->data;
751 parser = gst_element_factory_create (parserfact, NULL);
753 gst_plugin_feature_list_free (parsers);
759 _create_element_and_set_preset (GstElementFactory * factory,
760 const gchar * preset, const gchar * name)
762 GstElement *res = NULL;
764 GST_DEBUG ("Creating element from factory %s",
765 GST_PLUGIN_FEATURE_NAME (factory));
766 res = gst_element_factory_create (factory, name);
767 if (preset && GST_IS_PRESET (res) &&
768 !gst_preset_load_preset (GST_PRESET (res), preset)) {
769 GST_WARNING ("Couldn't set preset [%s] on element [%s]",
770 preset, GST_PLUGIN_FEATURE_NAME (factory));
771 gst_object_unref (res);
778 /* Create the encoder for the given stream profile */
779 static inline GstElement *
780 _get_encoder (GstEncodeBin * ebin, GstEncodingProfile * sprof)
782 GList *encoders, *tmp;
783 GstElement *encoder = NULL;
784 GstElementFactory *encoderfact = NULL;
785 const GstCaps *format;
788 format = gst_encoding_profile_get_format (sprof);
789 preset = gst_encoding_profile_get_preset (sprof);
791 GST_DEBUG ("Getting list of encoders for format %" GST_PTR_FORMAT, format);
793 /* If stream caps are raw, return identity */
794 if (G_UNLIKELY (are_raw_caps (format))) {
795 GST_DEBUG ("Stream format is raw, returning identity as the encoder");
796 encoder = gst_element_factory_make ("identity", NULL);
801 gst_element_factory_list_filter (ebin->encoders, format,
804 if (G_UNLIKELY (encoders == NULL)) {
805 GST_DEBUG ("Couldn't find any compatible encoders");
809 for (tmp = encoders; tmp; tmp = tmp->next) {
810 encoderfact = (GstElementFactory *) tmp->data;
811 if ((encoder = _create_element_and_set_preset (encoderfact, preset, NULL)))
815 gst_plugin_feature_list_free (encoders);
822 local_element_request_pad (GstElement * element, GstPadTemplate * templ,
825 GstPad *newpad = NULL;
826 GstElementClass *oclass;
828 oclass = GST_ELEMENT_GET_CLASS (element);
830 if (oclass->request_new_pad)
831 newpad = (oclass->request_new_pad) (element, templ, name);
834 gst_object_ref (newpad);
840 gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
843 GstPadPresence presence;
845 /* If this function is ever exported, we need check the validity of `element'
846 * and `templ', and to make sure the template actually belongs to the
849 presence = GST_PAD_TEMPLATE_PRESENCE (templ);
853 case GST_PAD_SOMETIMES:
854 ret = gst_element_get_static_pad (element, templ->name_template);
855 if (!ret && presence == GST_PAD_ALWAYS)
857 ("Element %s has an ALWAYS template %s, but no pad of the same name",
858 GST_OBJECT_NAME (element), templ->name_template);
861 case GST_PAD_REQUEST:
862 ret = gst_element_request_pad (element, templ, NULL, NULL);
869 /* FIXME : Improve algorithm for finding compatible muxer sink pad */
870 static inline GstPad *
871 get_compatible_muxer_sink_pad (GstEncodeBin * ebin, GstElement * encoder,
872 const GstCaps * sinkcaps)
875 GstPadTemplate *srctempl = NULL;
876 GstPadTemplate *sinktempl;
880 srcpad = gst_element_get_static_pad (encoder, "src");
882 srctempl = gst_pad_get_pad_template (srcpad);
884 GST_DEBUG_OBJECT (ebin,
885 "Attempting to find pad from muxer %s compatible with %s:%s",
886 GST_ELEMENT_NAME (ebin->muxer), GST_DEBUG_PAD_NAME (srcpad));
888 gst_object_unref (srcpad);
889 sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
892 gst_pad_template_new ("whatever", GST_PAD_SRC, GST_PAD_ALWAYS,
893 gst_caps_copy (sinkcaps));
894 g_assert (srctempl != NULL);
895 sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
896 g_object_unref (srctempl);
899 if (G_UNLIKELY (sinktempl == NULL))
902 sinkpad = gst_element_get_pad_from_template (ebin->muxer, sinktempl);
908 GST_WARNING_OBJECT (ebin, "No compatible pad available on muxer");
913 /* FIXME : Add handling of streams that don't need encoding */
914 /* FIXME : Add handling of streams that don't require conversion elements */
916 * Create the elements, StreamGroup, add the sink pad, link it to the muxer
918 * sinkpadname: If non-NULL, that name will be assigned to the sink ghost pad
919 * sinkcaps: If non-NULL will be used to figure out how to setup the group */
921 _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
922 const gchar * sinkpadname, GstCaps * sinkcaps)
924 StreamGroup *sgroup = NULL;
925 GstPad *sinkpad, *srcpad, *muxerpad = NULL;
926 /* Element we will link to the encoder */
927 GstElement *last = NULL;
928 GList *tmp, *tosync = NULL;
929 const GstCaps *format;
930 const GstCaps *restriction;
932 format = gst_encoding_profile_get_format (sprof);
933 restriction = gst_encoding_profile_get_restriction (sprof);
935 GST_DEBUG ("Creating group. format %" GST_PTR_FORMAT ", for caps %"
936 GST_PTR_FORMAT, format, sinkcaps);
937 GST_DEBUG ("avoid_reencoding:%d", ebin->avoid_reencoding);
939 sgroup = g_slice_new0 (StreamGroup);
941 sgroup->profile = sprof;
943 /* NOTE for people reading this code:
945 * We construct the group starting by the furthest downstream element
946 * and making our way up adding/syncing/linking as we go.
948 * There are two parallel paths:
949 * * One for raw data which goes through converters and encoders
950 * * One for already encoded data
953 /* Exception to the rule above:
954 * We check if we have an available encoder so we can abort early */
955 /* FIXME : What if we only want to do passthrough ??? */
956 GST_LOG ("Checking for encoder availability");
957 sgroup->encoder = _get_encoder (ebin, sprof);
958 if (G_UNLIKELY (sgroup->encoder == NULL))
962 * If we are handling a container profile, figure out if the muxer has a
963 * sinkpad compatible with the selected profile */
965 muxerpad = get_compatible_muxer_sink_pad (ebin, NULL, format);
966 if (G_UNLIKELY (muxerpad == NULL))
971 * We only use a 1buffer long queue here, the actual queueing will be done
972 * in the intput queue */
973 last = sgroup->outqueue = gst_element_factory_make ("queue", NULL);
974 g_object_set (sgroup->outqueue, "max-size-buffers", (guint32) 1,
975 "max-size-bytes", (guint32) 0, "max-size-time", (guint64) 0, NULL);
977 gst_bin_add (GST_BIN (ebin), sgroup->outqueue);
978 tosync = g_list_append (tosync, sgroup->outqueue);
979 srcpad = gst_element_get_static_pad (sgroup->outqueue, "src");
981 if (G_UNLIKELY (fast_pad_link (srcpad, muxerpad) != GST_PAD_LINK_OK)) {
982 goto muxer_link_failure;
984 gst_object_unref (muxerpad);
986 gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), srcpad);
988 gst_object_unref (srcpad);
991 * This will receive the format caps from the streamprofile */
992 GST_DEBUG ("Adding output capsfilter for %" GST_PTR_FORMAT, format);
993 sgroup->outfilter = gst_element_factory_make ("capsfilter", NULL);
994 g_object_set (sgroup->outfilter, "caps", format, NULL);
996 gst_bin_add (GST_BIN (ebin), sgroup->outfilter);
997 tosync = g_list_append (tosync, sgroup->outfilter);
998 if (G_UNLIKELY (!fast_element_link (sgroup->outfilter, last)))
999 goto outfilter_link_failure;
1000 last = sgroup->outfilter;
1005 * The usage of parsers in encoding/muxing scenarios is
1006 * just too undefined to just use as-is.
1008 * Take the use-case where you want to re-mux a stream of type
1009 * "my/media". You create a StreamEncodingProfile with that type
1010 * as the target (as-is). And you use decodebin2/uridecodebin
1013 * * demuxer exposes "my/media"
1014 * * a parser is available for "my/media" which has a source pad
1015 * caps of "my/media,parsed=True"
1016 * * decodebin2/uridecodebin exposes a new pad with the parsed caps
1017 * * You request a new stream from encodebin, which will match the
1018 * streamprofile and creates a group (i.e. going through this method)
1019 * There is a matching parser (the same used in the decoder) whose
1020 * source pad caps intersects with the stream profile caps, you
1021 * therefore use it...
1022 * * ... but that parser has a "my/media,parsed=False" sink pad caps
1023 * * ... and you can't link your decodebin pad to encodebin.
1025 * In the end, it comes down to parsers only taking into account the
1026 * decoding use-cases.
1028 * One way to solve that might be to :
1029 * * Make parsers sink pad caps be "framed={False,True}" and the
1030 * source pad caps be "framed=True"
1031 * * Modify decodebin2 accordingly to avoid looping and chaining
1032 * an infinite number of parsers
1034 * Another way would be to have "well-known" caps properties to specify
1035 * whether a stream has been parsed or not.
1036 * * currently we fail. aacparse uses 'framed' and mp3parse uses 'parsed'
1038 /* FIXME : Re-enable once parser situation is un-$#*@(%$#ed */
1041 * FIXME : identify smart parsers (used for re-encoding) */
1042 sgroup->parser = _get_parser (ebin, sprof);
1044 if (sgroup->parser != NULL) {
1045 GST_DEBUG ("Got a parser %s", GST_ELEMENT_NAME (sgroup->parser));
1046 gst_bin_add (GST_BIN (ebin), sgroup->parser);
1047 tosync = g_list_append (tosync, sgroup->parser);
1048 if (G_UNLIKELY (!gst_element_link (sgroup->parser, last)))
1049 goto parser_link_failure;
1050 last = sgroup->parser;
1054 /* Stream combiner */
1055 sgroup->combiner = g_object_new (GST_TYPE_STREAM_COMBINER, NULL);
1057 gst_bin_add (GST_BIN (ebin), sgroup->combiner);
1058 tosync = g_list_append (tosync, sgroup->combiner);
1059 if (G_UNLIKELY (!fast_element_link (sgroup->combiner, last)))
1060 goto combiner_link_failure;
1063 /* Stream splitter */
1064 sgroup->splitter = g_object_new (GST_TYPE_STREAM_SPLITTER, NULL);
1066 gst_bin_add (GST_BIN (ebin), sgroup->splitter);
1067 tosync = g_list_append (tosync, sgroup->splitter);
1070 * FIXME : figure out what max-size to use for the input queue */
1071 sgroup->inqueue = gst_element_factory_make ("queue", NULL);
1072 g_object_set (sgroup->inqueue, "max-size-buffers",
1073 (guint32) ebin->queue_buffers_max, "max-size-bytes",
1074 (guint32) ebin->queue_bytes_max, "max-size-time",
1075 (guint64) ebin->queue_time_max, NULL);
1077 gst_bin_add (GST_BIN (ebin), sgroup->inqueue);
1078 tosync = g_list_append (tosync, sgroup->inqueue);
1079 if (G_UNLIKELY (!fast_element_link (sgroup->inqueue, sgroup->splitter)))
1080 goto splitter_link_failure;
1082 /* Expose input queue sink pad as ghostpad */
1083 sinkpad = gst_element_get_static_pad (sgroup->inqueue, "sink");
1084 if (sinkpadname == NULL) {
1086 g_strdup_printf ("%s_%d", gst_encoding_profile_get_type_nick (sprof),
1087 ebin->last_pad_id++);
1088 GST_DEBUG ("Adding ghost pad %s", pname);
1089 sgroup->ghostpad = gst_ghost_pad_new (pname, sinkpad);
1092 sgroup->ghostpad = gst_ghost_pad_new (sinkpadname, sinkpad);
1093 gst_object_unref (sinkpad);
1096 /* Path 1 : Already-encoded data */
1098 local_element_request_pad (sgroup->combiner, NULL, "passthroughsink");
1099 if (G_UNLIKELY (sinkpad == NULL))
1100 goto no_combiner_sinkpad;
1102 if (ebin->avoid_reencoding) {
1105 GST_DEBUG ("Asked to use Smart Encoder");
1106 sgroup->smartencoder = g_object_new (GST_TYPE_SMART_ENCODER, NULL);
1108 /* Check if stream format is compatible */
1109 srcpad = gst_element_get_static_pad (sgroup->smartencoder, "src");
1110 tmpcaps = gst_pad_get_caps (srcpad);
1111 if (!gst_caps_can_intersect (tmpcaps, format)) {
1112 GST_DEBUG ("We don't have a smart encoder for the stream format");
1113 gst_object_unref (sgroup->smartencoder);
1114 sgroup->smartencoder = NULL;
1116 gst_bin_add ((GstBin *) ebin, sgroup->smartencoder);
1117 fast_pad_link (srcpad, sinkpad);
1118 tosync = g_list_append (tosync, sgroup->smartencoder);
1119 sinkpad = gst_element_get_static_pad (sgroup->smartencoder, "sink");
1121 gst_caps_unref (tmpcaps);
1122 g_object_unref (srcpad);
1125 srcpad = local_element_request_pad (sgroup->splitter, NULL, "passthroughsrc");
1126 if (G_UNLIKELY (srcpad == NULL))
1127 goto no_splitter_srcpad;
1129 /* Go straight to splitter */
1130 if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1131 goto passthrough_link_failure;
1132 g_object_unref (sinkpad);
1133 g_object_unref (srcpad);
1136 /* Path 2 : Conversion / Encoding */
1138 /* 1. Create the encoder */
1139 GST_LOG ("Adding encoder");
1140 last = sgroup->encoder;
1141 gst_bin_add ((GstBin *) ebin, sgroup->encoder);
1142 tosync = g_list_append (tosync, sgroup->encoder);
1144 sinkpad = local_element_request_pad (sgroup->combiner, NULL, "encodingsink");
1145 if (G_UNLIKELY (sinkpad == NULL))
1146 goto no_combiner_sinkpad;
1147 srcpad = gst_element_get_static_pad (sgroup->encoder, "src");
1148 if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1149 goto encoder_link_failure;
1150 g_object_unref (sinkpad);
1151 g_object_unref (srcpad);
1154 /* 3. Create the conversion/restriction elements */
1155 /* 3.1. capsfilter */
1156 if (restriction && !gst_caps_is_any (restriction)) {
1157 GST_LOG ("Adding capsfilter for restriction caps : %" GST_PTR_FORMAT,
1160 last = sgroup->capsfilter = gst_element_factory_make ("capsfilter", NULL);
1161 g_object_set (sgroup->capsfilter, "caps", restriction, NULL);
1162 gst_bin_add ((GstBin *) ebin, sgroup->capsfilter);
1163 tosync = g_list_append (tosync, sgroup->capsfilter);
1164 fast_element_link (sgroup->capsfilter, sgroup->encoder);
1167 /* 3.2. restriction elements */
1168 /* FIXME : Once we have properties for specific converters, use those */
1169 if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
1170 GstElement *cspace, *scale, *vrate, *cspace2;
1172 GST_LOG ("Adding conversion elements for video stream");
1174 cspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
1175 scale = gst_element_factory_make ("videoscale", NULL);
1176 /* 4-tap scaling and black borders */
1177 g_object_set (scale, "method", 2, "add-borders", TRUE, NULL);
1178 cspace2 = gst_element_factory_make ("ffmpegcolorspace", NULL);
1180 gst_bin_add_many ((GstBin *) ebin, cspace, scale, cspace2, NULL);
1181 tosync = g_list_append (tosync, cspace);
1182 tosync = g_list_append (tosync, scale);
1183 tosync = g_list_append (tosync, cspace2);
1185 sgroup->converters = g_list_prepend (sgroup->converters, cspace);
1186 sgroup->converters = g_list_prepend (sgroup->converters, scale);
1187 sgroup->converters = g_list_prepend (sgroup->converters, cspace2);
1189 if (!fast_element_link (cspace, scale) ||
1190 !fast_element_link (scale, cspace2))
1191 goto converter_link_failure;
1193 if (!gst_encoding_video_profile_get_variableframerate
1194 (GST_ENCODING_VIDEO_PROFILE (sprof))) {
1195 vrate = gst_element_factory_make ("videorate", NULL);
1196 gst_bin_add ((GstBin *) ebin, vrate);
1197 tosync = g_list_prepend (tosync, vrate);
1198 sgroup->converters = g_list_prepend (sgroup->converters, vrate);
1199 if (!fast_element_link (cspace2, vrate) ||
1200 !fast_element_link (vrate, last))
1201 goto converter_link_failure;
1202 } else if (!fast_element_link (cspace2, last))
1203 goto converter_link_failure;
1207 } else if (GST_IS_ENCODING_AUDIO_PROFILE (sprof)) {
1208 GstElement *aconv, *ares, *arate, *aconv2;
1210 GST_LOG ("Adding conversion elements for audio stream");
1212 arate = gst_element_factory_make ("audiorate", NULL);
1213 g_object_set (arate, "tolerance", (guint64) ebin->tolerance, NULL);
1214 aconv = gst_element_factory_make ("audioconvert", NULL);
1215 aconv2 = gst_element_factory_make ("audioconvert", NULL);
1216 ares = gst_element_factory_make ("audioresample", NULL);
1218 gst_bin_add_many ((GstBin *) ebin, arate, aconv, ares, aconv2, NULL);
1219 tosync = g_list_append (tosync, arate);
1220 tosync = g_list_append (tosync, aconv);
1221 tosync = g_list_append (tosync, ares);
1222 tosync = g_list_append (tosync, aconv2);
1223 if (!fast_element_link (arate, aconv) ||
1224 !fast_element_link (aconv, ares) ||
1225 !fast_element_link (ares, aconv2) || !fast_element_link (aconv2, last))
1226 goto converter_link_failure;
1228 sgroup->converters = g_list_prepend (sgroup->converters, arate);
1229 sgroup->converters = g_list_prepend (sgroup->converters, aconv);
1230 sgroup->converters = g_list_prepend (sgroup->converters, ares);
1231 sgroup->converters = g_list_prepend (sgroup->converters, aconv2);
1236 /* Link to stream splitter */
1237 sinkpad = gst_element_get_static_pad (last, "sink");
1238 srcpad = local_element_request_pad (sgroup->splitter, NULL, "encodingsrc");
1239 if (G_UNLIKELY (srcpad == NULL))
1240 goto no_splitter_srcpad;
1241 if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1242 goto splitter_encoding_failure;
1243 g_object_unref (sinkpad);
1244 g_object_unref (srcpad);
1246 /* End of Stream 2 setup */
1248 /* Sync all elements to parent state */
1249 for (tmp = tosync; tmp; tmp = tmp->next)
1250 gst_element_sync_state_with_parent ((GstElement *) tmp->data);
1251 g_list_free (tosync);
1254 GST_DEBUG ("Adding ghostpad %s:%s", GST_DEBUG_PAD_NAME (sgroup->ghostpad));
1255 gst_pad_set_active (sgroup->ghostpad, TRUE);
1256 gst_element_add_pad ((GstElement *) ebin, sgroup->ghostpad);
1258 /* Add StreamGroup to our list of streams */
1261 ("Done creating elements, adding StreamGroup to our controlled stream list");
1263 ebin->streams = g_list_prepend (ebin->streams, sgroup);
1267 splitter_encoding_failure:
1268 GST_ERROR_OBJECT (ebin, "Error linking splitter to encoding stream");
1272 GST_ERROR_OBJECT (ebin, "Couldn't create encoder for format %" GST_PTR_FORMAT,
1274 /* missing plugin support */
1275 gst_element_post_message (GST_ELEMENT_CAST (ebin),
1276 gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format));
1277 GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL),
1278 ("Couldn't create encoder for format %" GST_PTR_FORMAT, format));
1282 GST_ERROR_OBJECT (ebin,
1283 "Couldn't find a compatible muxer pad to link encoder to");
1286 encoder_link_failure:
1287 GST_ERROR_OBJECT (ebin, "Failed to link the encoder");
1291 GST_ERROR_OBJECT (ebin, "Couldn't link encoder to muxer");
1294 outfilter_link_failure:
1295 GST_ERROR_OBJECT (ebin, "Couldn't link output filter to output queue");
1298 passthrough_link_failure:
1299 GST_ERROR_OBJECT (ebin, "Failed linking splitter in passthrough mode");
1303 GST_ERROR_OBJECT (ebin, "Couldn't get a source pad from the splitter");
1306 no_combiner_sinkpad:
1307 GST_ERROR_OBJECT (ebin, "Couldn't get a sink pad from the combiner");
1310 splitter_link_failure:
1311 GST_ERROR_OBJECT (ebin, "Failure linking to the splitter");
1314 combiner_link_failure:
1315 GST_ERROR_OBJECT (ebin, "Failure linking to the combiner");
1319 parser_link_failure:
1320 GST_ERROR_OBJECT (ebin, "Failure linking the parser");
1324 converter_link_failure:
1325 GST_ERROR_OBJECT (ebin, "Failure linking the video converters");
1329 /* FIXME : Actually properly cleanup everything */
1330 g_slice_free (StreamGroup, sgroup);
1335 _factory_can_sink_caps (GstElementFactory * factory, const GstCaps * caps)
1337 GList *templates = factory->staticpadtemplates;
1340 GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
1342 if (template->direction == GST_PAD_SINK) {
1343 GstCaps *tmp = gst_static_caps_get (&template->static_caps);
1345 if (gst_caps_can_intersect (tmp, caps)) {
1346 gst_caps_unref (tmp);
1349 gst_caps_unref (tmp);
1351 templates = g_list_next (templates);
1357 static inline GstElement *
1358 _get_muxer (GstEncodeBin * ebin)
1360 GList *muxers, *tmpmux;
1361 GstElement *muxer = NULL;
1362 GstElementFactory *muxerfact = NULL;
1364 const GstCaps *format;
1365 const gchar *preset;
1367 format = gst_encoding_profile_get_format (ebin->profile);
1368 preset = gst_encoding_profile_get_preset (ebin->profile);
1370 GST_DEBUG ("Getting list of muxers for format %" GST_PTR_FORMAT, format);
1373 gst_element_factory_list_filter (ebin->muxers, format, GST_PAD_SRC, TRUE);
1378 /* FIXME : signal the user if he wants this */
1379 for (tmpmux = muxers; tmpmux; tmpmux = tmpmux->next) {
1380 gboolean cansinkstreams = TRUE;
1381 const GList *profiles =
1382 gst_encoding_container_profile_get_profiles
1383 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
1385 muxerfact = (GstElementFactory *) tmpmux->data;
1387 GST_DEBUG ("Trying muxer %s", GST_PLUGIN_FEATURE_NAME (muxerfact));
1389 /* See if the muxer can sink all of our stream profile caps */
1390 for (tmp = profiles; tmp; tmp = tmp->next) {
1391 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
1393 if (!_factory_can_sink_caps (muxerfact,
1394 gst_encoding_profile_get_format (sprof))) {
1395 GST_DEBUG ("Skipping muxer because it can't sink caps %" GST_PTR_FORMAT,
1396 gst_encoding_profile_get_format (sprof));
1397 cansinkstreams = FALSE;
1402 /* Only use a muxer than can use all streams and than can accept the
1403 * preset (which may be present or not) */
1404 if (cansinkstreams && (muxer =
1405 _create_element_and_set_preset (muxerfact, preset, "muxer")))
1409 gst_plugin_feature_list_free (muxers);
1416 create_elements_and_pads (GstEncodeBin * ebin)
1418 gboolean ret = TRUE;
1419 GstElement *muxer = NULL;
1421 const GList *tmp, *profiles;
1422 GstEncodingProfile *sprof;
1424 GST_DEBUG ("Current profile : %s",
1425 gst_encoding_profile_get_name (ebin->profile));
1427 if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
1428 /* 1. Get the compatible muxer */
1429 muxer = _get_muxer (ebin);
1430 if (G_UNLIKELY (muxer == NULL))
1433 /* Record the muxer */
1434 ebin->muxer = muxer;
1435 gst_bin_add ((GstBin *) ebin, muxer);
1437 /* 2. Ghost the muxer source pad */
1439 /* FIXME : We should figure out if it's a static/request/dyamic pad,
1440 * but for the time being let's assume it's a static pad :) */
1441 muxerpad = gst_element_get_static_pad (muxer, "src");
1442 if (G_UNLIKELY (muxerpad == NULL))
1445 if (!gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), muxerpad))
1446 goto no_muxer_ghost_pad;
1448 gst_object_unref (muxerpad);
1449 /* 3. Activate fixed presence streams */
1451 gst_encoding_container_profile_get_profiles
1452 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
1453 for (tmp = profiles; tmp; tmp = tmp->next) {
1454 sprof = (GstEncodingProfile *) tmp->data;
1456 GST_DEBUG ("Trying stream profile with presence %d",
1457 gst_encoding_profile_get_presence (sprof));
1459 if (gst_encoding_profile_get_presence (sprof) != 0) {
1460 if (G_UNLIKELY (_create_stream_group (ebin, sprof, NULL, NULL) == NULL))
1465 if (G_UNLIKELY (_create_stream_group (ebin, ebin->profile, NULL,
1474 GST_WARNING ("No available muxer for %" GST_PTR_FORMAT,
1475 gst_encoding_profile_get_format (ebin->profile));
1476 /* missing plugin support */
1477 gst_element_post_message (GST_ELEMENT_CAST (ebin),
1478 gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin),
1479 gst_encoding_profile_get_format (ebin->profile)));
1480 GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL),
1481 ("No available muxer for format %" GST_PTR_FORMAT,
1482 gst_encoding_profile_get_format (ebin->profile)));
1488 GST_WARNING ("Can't get source pad from muxer (%s)",
1489 GST_ELEMENT_NAME (muxer));
1490 gst_bin_remove (GST_BIN (ebin), muxer);
1496 GST_WARNING ("Couldn't set %s:%s as source ghostpad target",
1497 GST_DEBUG_PAD_NAME (muxerpad));
1498 gst_bin_remove (GST_BIN (ebin), muxer);
1499 gst_object_unref (muxerpad);
1505 GST_WARNING ("Could not create Streams");
1507 gst_bin_remove (GST_BIN (ebin), muxer);
1514 release_pads (GstPad * pad, GstElement * elt)
1516 GstPad *peer = NULL;
1518 GST_DEBUG_OBJECT (elt, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1520 /* Unlink from its peer pad */
1521 if ((peer = gst_pad_get_peer (pad))) {
1522 if (GST_PAD_DIRECTION (peer) == GST_PAD_SRC)
1523 gst_pad_unlink (peer, pad);
1525 gst_pad_unlink (pad, peer);
1526 gst_object_unref (peer);
1529 /* Release it from the object */
1530 gst_element_release_request_pad (elt, pad);
1532 /* And remove the reference added by the iterator */
1533 gst_object_unref (pad);
1537 stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup)
1543 GST_DEBUG_OBJECT (ebin, "Freeing StreamGroup %p", sgroup);
1546 /* outqueue - Muxer */
1547 tmppad = gst_element_get_static_pad (sgroup->outqueue, "src");
1548 pad = gst_pad_get_peer (tmppad);
1550 /* Remove muxer request sink pad */
1551 gst_pad_unlink (tmppad, pad);
1552 gst_element_release_request_pad (ebin->muxer, pad);
1553 gst_object_unref (tmppad);
1554 gst_object_unref (pad);
1556 if (sgroup->outqueue)
1557 gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
1559 /* Capsfilter - outqueue */
1560 gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
1561 gst_element_unlink (sgroup->outfilter, sgroup->outqueue);
1562 gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
1563 gst_bin_remove (GST_BIN (ebin), sgroup->outqueue);
1565 /* streamcombiner - parser - capsfilter */
1566 if (sgroup->parser) {
1567 gst_element_set_state (sgroup->parser, GST_STATE_NULL);
1568 gst_element_unlink (sgroup->parser, sgroup->outfilter);
1569 gst_element_unlink (sgroup->combiner, sgroup->parser);
1570 gst_bin_remove ((GstBin *) ebin, sgroup->parser);
1574 if (sgroup->ghostpad)
1575 gst_element_remove_pad (GST_ELEMENT_CAST (ebin), sgroup->ghostpad);
1577 if (sgroup->inqueue)
1578 gst_element_set_state (sgroup->inqueue, GST_STATE_NULL);
1580 if (sgroup->encoder)
1581 gst_element_set_state (sgroup->encoder, GST_STATE_NULL);
1582 if (sgroup->outfilter)
1583 gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
1584 if (sgroup->smartencoder)
1585 gst_element_set_state (sgroup->smartencoder, GST_STATE_NULL);
1587 if (sgroup->capsfilter) {
1588 gst_element_set_state (sgroup->capsfilter, GST_STATE_NULL);
1589 gst_element_unlink (sgroup->capsfilter, sgroup->encoder);
1590 gst_bin_remove ((GstBin *) ebin, sgroup->capsfilter);
1593 for (tmp = sgroup->converters; tmp; tmp = tmp->next) {
1594 GstElement *elt = (GstElement *) tmp->data;
1596 gst_element_set_state (elt, GST_STATE_NULL);
1597 gst_bin_remove ((GstBin *) ebin, elt);
1599 if (sgroup->converters)
1600 g_list_free (sgroup->converters);
1602 if (sgroup->combiner) {
1603 GstIterator *it = gst_element_iterate_sink_pads (sgroup->combiner);
1604 GstIteratorResult itret = GST_ITERATOR_OK;
1606 while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
1607 itret = gst_iterator_foreach (it, (GFunc) release_pads, sgroup->combiner);
1608 gst_iterator_resync (it);
1610 gst_iterator_free (it);
1611 gst_element_set_state (sgroup->combiner, GST_STATE_NULL);
1612 gst_bin_remove ((GstBin *) ebin, sgroup->combiner);
1615 if (sgroup->splitter) {
1616 GstIterator *it = gst_element_iterate_src_pads (sgroup->splitter);
1617 GstIteratorResult itret = GST_ITERATOR_OK;
1618 while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
1619 itret = gst_iterator_foreach (it, (GFunc) release_pads, sgroup->splitter);
1620 gst_iterator_resync (it);
1622 gst_iterator_free (it);
1624 gst_element_set_state (sgroup->splitter, GST_STATE_NULL);
1625 gst_bin_remove ((GstBin *) ebin, sgroup->splitter);
1628 if (sgroup->inqueue)
1629 gst_bin_remove ((GstBin *) ebin, sgroup->inqueue);
1631 if (sgroup->encoder)
1632 gst_bin_remove ((GstBin *) ebin, sgroup->encoder);
1634 if (sgroup->smartencoder)
1635 gst_bin_remove ((GstBin *) ebin, sgroup->smartencoder);
1637 if (sgroup->outfilter)
1638 gst_bin_remove ((GstBin *) ebin, sgroup->outfilter);
1640 g_slice_free (StreamGroup, sgroup);
1644 stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup)
1646 ebin->streams = g_list_remove (ebin->streams, sgroup);
1648 stream_group_free (ebin, sgroup);
1652 gst_encode_bin_tear_down_profile (GstEncodeBin * ebin)
1654 if (G_UNLIKELY (ebin->profile == NULL))
1657 GST_DEBUG ("Tearing down profile %s",
1658 gst_encoding_profile_get_name (ebin->profile));
1660 while (ebin->streams)
1661 stream_group_remove (ebin, (StreamGroup *) ebin->streams->data);
1663 /* Set ghostpad target to NULL */
1664 gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), NULL);
1666 /* Remove muxer if present */
1668 gst_element_set_state (ebin->muxer, GST_STATE_NULL);
1669 gst_bin_remove (GST_BIN (ebin), ebin->muxer);
1673 /* free/clear profile */
1674 gst_encoding_profile_unref (ebin->profile);
1675 ebin->profile = NULL;
1679 gst_encode_bin_setup_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
1683 g_return_val_if_fail (ebin->profile == NULL, FALSE);
1685 GST_DEBUG ("Setting up profile %s (type:%s)",
1686 gst_encoding_profile_get_name (profile),
1687 gst_encoding_profile_get_type_nick (profile));
1689 ebin->profile = profile;
1690 gst_mini_object_ref ((GstMiniObject *) ebin->profile);
1692 /* Create elements */
1693 res = create_elements_and_pads (ebin);
1695 gst_encode_bin_tear_down_profile (ebin);
1701 gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
1703 g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
1705 GST_DEBUG_OBJECT (ebin, "profile : %s",
1706 gst_encoding_profile_get_name (profile));
1708 if (G_UNLIKELY (ebin->active)) {
1709 GST_WARNING_OBJECT (ebin, "Element already active, can't change profile");
1713 /* If we're not active, we can deactivate the previous profile */
1714 if (ebin->profile) {
1715 gst_encode_bin_tear_down_profile (ebin);
1718 return gst_encode_bin_setup_profile (ebin, profile);
1721 static inline gboolean
1722 gst_encode_bin_activate (GstEncodeBin * ebin)
1724 ebin->active = ebin->profile != NULL;
1725 return ebin->active;
1729 gst_encode_bin_deactivate (GstEncodeBin * ebin)
1731 ebin->active = FALSE;
1734 static GstStateChangeReturn
1735 gst_encode_bin_change_state (GstElement * element, GstStateChange transition)
1737 GstStateChangeReturn ret;
1738 GstEncodeBin *ebin = (GstEncodeBin *) element;
1740 switch (transition) {
1741 case GST_STATE_CHANGE_READY_TO_PAUSED:
1742 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1743 if (!gst_encode_bin_activate (ebin)) {
1744 ret = GST_STATE_CHANGE_FAILURE;
1753 GST_ELEMENT_CLASS (gst_encode_bin_parent_class)->change_state (element,
1755 if (ret == GST_STATE_CHANGE_FAILURE)
1758 switch (transition) {
1759 case GST_STATE_CHANGE_PAUSED_TO_READY:
1760 gst_encode_bin_deactivate (ebin);
1772 plugin_init (GstPlugin * plugin)
1776 GST_DEBUG_CATEGORY_INIT (gst_encode_bin_debug, "encodebin", 0, "encoder bin");
1779 GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
1781 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
1782 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
1783 #endif /* ENABLE_NLS */
1786 res = gst_element_register (plugin, "encodebin", GST_RANK_NONE,
1787 GST_TYPE_ENCODE_BIN);
1792 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1795 "various encoding-related elements", plugin_init, VERSION, GST_LICENSE,
1796 GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)