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
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 isn't '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)
123 GST_ENCODEBIN_FLAG_NO_AUDIO_CONVERSION = (1 << 0),
124 GST_ENCODEBIN_FLAG_NO_VIDEO_CONVERSION = (1 << 1)
127 #define GST_TYPE_ENCODEBIN_FLAGS (gst_encodebin_flags_get_type())
128 GType gst_encodebin_flags_get_type (void);
130 /* generic templates */
131 static GstStaticPadTemplate muxer_src_template =
132 GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,
133 GST_STATIC_CAPS_ANY);
135 static GstStaticPadTemplate video_sink_template =
136 GST_STATIC_PAD_TEMPLATE ("video_%u",
139 GST_STATIC_CAPS_ANY);
140 static GstStaticPadTemplate audio_sink_template =
141 GST_STATIC_PAD_TEMPLATE ("audio_%u",
144 GST_STATIC_CAPS_ANY);
145 /* static GstStaticPadTemplate text_sink_template = */
146 /* GST_STATIC_PAD_TEMPLATE ("text_%u", */
148 /* GST_PAD_REQUEST, */
149 /* GST_STATIC_CAPS_ANY); */
150 static GstStaticPadTemplate private_sink_template =
151 GST_STATIC_PAD_TEMPLATE ("private_%u",
154 GST_STATIC_CAPS_ANY);
160 /* the profile field is only valid if it could be entirely setup */
161 GstEncodingProfile *profile;
163 GList *streams; /* List of StreamGroup, not sorted */
166 /* Ghostpad with changing target */
169 /* TRUE if in PAUSED/PLAYING */
172 /* available muxers, encoders and parsers */
178 /* Increasing counter for unique pad name */
181 /* Cached caps for identification */
182 GstCaps *raw_video_caps;
183 GstCaps *raw_audio_caps;
184 /* GstCaps *raw_text_caps; */
186 guint queue_buffers_max;
187 guint queue_bytes_max;
188 guint64 queue_time_max;
191 gboolean avoid_reencoding;
193 GstEncodeBinFlags flags;
196 struct _GstEncodeBinClass
201 GstPad *(*request_pad) (GstEncodeBin * encodebin, GstCaps * caps);
202 GstPad *(*request_profile_pad) (GstEncodeBin * encodebin,
203 const gchar * profilename);
206 typedef struct _StreamGroup StreamGroup;
211 GstEncodingProfile *profile;
212 GstPad *ghostpad; /* Sink ghostpad */
213 GstElement *inqueue; /* Queue just after the ghostpad */
214 GstElement *splitter;
215 GList *converters; /* List of conversion GstElement */
216 GstElement *capsfilter; /* profile->restriction (if non-NULL/ANY) */
217 GstElement *encoder; /* Encoder (can be NULL) */
218 GstElement *fakesink; /* Fakesink (can be NULL) */
219 GstElement *combiner;
221 GstElement *smartencoder;
222 GstElement *outfilter; /* Output capsfilter (streamprofile.format) */
223 gulong outputfilter_caps_sid;
224 GstElement *formatter;
225 GstElement *outqueue; /* Queue just before the muxer */
226 gulong restriction_sid;
229 /* Default for queues (same defaults as queue element) */
230 #define DEFAULT_QUEUE_BUFFERS_MAX 200
231 #define DEFAULT_QUEUE_BYTES_MAX 10 * 1024 * 1024
232 #define DEFAULT_QUEUE_TIME_MAX GST_SECOND
233 #define DEFAULT_AUDIO_JITTER_TOLERANCE 20 * GST_MSECOND
234 #define DEFAULT_AVOID_REENCODING FALSE
235 #define DEFAULT_FLAGS 0
237 #define DEFAULT_RAW_CAPS \
241 "subpicture/x-dvd; " \
249 PROP_QUEUE_BUFFERS_MAX,
250 PROP_QUEUE_BYTES_MAX,
252 PROP_AUDIO_JITTER_TOLERANCE,
253 PROP_AVOID_REENCODING,
262 SIGNAL_REQUEST_PROFILE_PAD,
266 #define C_FLAGS(v) ((guint) v)
269 gst_encodebin_flags_get_type (void)
271 static const GFlagsValue values[] = {
272 {C_FLAGS (GST_ENCODEBIN_FLAG_NO_AUDIO_CONVERSION), "Do not use audio "
273 "conversion elements", "no-audio-conversion"},
274 {C_FLAGS (GST_ENCODEBIN_FLAG_NO_VIDEO_CONVERSION), "Do not use video "
275 "conversion elements", "no-video-conversion"},
278 static volatile GType id = 0;
280 if (g_once_init_enter ((gsize *) & id)) {
283 _id = g_flags_register_static ("GstEncodeBinFlags", values);
285 g_once_init_leave ((gsize *) & id, _id);
291 static guint gst_encode_bin_signals[LAST_SIGNAL] = { 0 };
293 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
295 GST_DEBUG_CATEGORY_STATIC (gst_encode_bin_debug);
296 #define GST_CAT_DEFAULT gst_encode_bin_debug
298 G_DEFINE_TYPE (GstEncodeBin, gst_encode_bin, GST_TYPE_BIN);
300 static void gst_encode_bin_dispose (GObject * object);
301 static void gst_encode_bin_set_property (GObject * object, guint prop_id,
302 const GValue * value, GParamSpec * pspec);
303 static void gst_encode_bin_get_property (GObject * object, guint prop_id,
304 GValue * value, GParamSpec * pspec);
305 static GstStateChangeReturn gst_encode_bin_change_state (GstElement * element,
306 GstStateChange transition);
308 static GstPad *gst_encode_bin_request_new_pad (GstElement * element,
309 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
310 static void gst_encode_bin_release_pad (GstElement * element, GstPad * pad);
313 gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile);
314 static void gst_encode_bin_tear_down_profile (GstEncodeBin * ebin);
315 static gboolean gst_encode_bin_setup_profile (GstEncodeBin * ebin,
316 GstEncodingProfile * profile);
318 static StreamGroup *_create_stream_group (GstEncodeBin * ebin,
319 GstEncodingProfile * sprof, const gchar * sinkpadname, GstCaps * sinkcaps);
320 static void stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup);
321 static void stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup);
322 static GstPad *gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin,
324 static GstPad *gst_encode_bin_request_profile_pad_signal (GstEncodeBin *
325 encodebin, const gchar * profilename);
327 static inline GstElement *_get_formatter (GstEncodeBin * ebin,
328 GstEncodingProfile * sprof);
331 gst_encode_bin_class_init (GstEncodeBinClass * klass)
333 GObjectClass *gobject_klass;
334 GstElementClass *gstelement_klass;
336 gobject_klass = (GObjectClass *) klass;
337 gstelement_klass = (GstElementClass *) klass;
339 gobject_klass->dispose = gst_encode_bin_dispose;
340 gobject_klass->set_property = gst_encode_bin_set_property;
341 gobject_klass->get_property = gst_encode_bin_get_property;
346 * GstEncodeBin:profile:
348 * The #GstEncodingProfile to use. This property must be set before going
349 * to %GST_STATE_PAUSED or higher.
351 g_object_class_install_property (gobject_klass, PROP_PROFILE,
352 g_param_spec_object ("profile", "Profile",
353 "The GstEncodingProfile to use", GST_TYPE_ENCODING_PROFILE,
354 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
356 g_object_class_install_property (gobject_klass, PROP_QUEUE_BYTES_MAX,
357 g_param_spec_uint ("queue-bytes-max", "Max. size (kB)",
358 "Max. amount of data in the queue (bytes, 0=disable)",
359 0, G_MAXUINT, DEFAULT_QUEUE_BYTES_MAX,
360 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
362 g_object_class_install_property (gobject_klass, PROP_QUEUE_BUFFERS_MAX,
363 g_param_spec_uint ("queue-buffers-max", "Max. size (buffers)",
364 "Max. number of buffers in the queue (0=disable)", 0, G_MAXUINT,
365 DEFAULT_QUEUE_BUFFERS_MAX,
366 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
368 g_object_class_install_property (gobject_klass, PROP_QUEUE_TIME_MAX,
369 g_param_spec_uint64 ("queue-time-max", "Max. size (ns)",
370 "Max. amount of data in the queue (in ns, 0=disable)", 0, G_MAXUINT64,
371 DEFAULT_QUEUE_TIME_MAX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
373 g_object_class_install_property (gobject_klass, PROP_AUDIO_JITTER_TOLERANCE,
374 g_param_spec_uint64 ("audio-jitter-tolerance", "Audio jitter tolerance",
375 "Amount of timestamp jitter/imperfection to allow on audio streams before inserting/dropping samples (ns)",
376 0, G_MAXUINT64, DEFAULT_AUDIO_JITTER_TOLERANCE,
377 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
379 g_object_class_install_property (gobject_klass, PROP_AVOID_REENCODING,
380 g_param_spec_boolean ("avoid-reencoding", "Avoid re-encoding",
381 "Whether to re-encode portions of compatible video streams that lay on segment boundaries",
382 DEFAULT_AVOID_REENCODING,
383 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
388 * Control the behaviour of encodebin.
390 g_object_class_install_property (gobject_klass, PROP_FLAGS,
391 g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
392 GST_TYPE_ENCODEBIN_FLAGS, DEFAULT_FLAGS,
393 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
397 * GstEncodeBin::request-pad
398 * @encodebin: a #GstEncodeBin instance
401 * Use this method to request an unused sink request #GstPad that can take the
402 * provided @caps as input. You must release the pad with
403 * gst_element_release_request_pad() when you are done with it.
405 * Returns: A compatible #GstPad, or %NULL if no compatible #GstPad could be
406 * created or is available.
408 gst_encode_bin_signals[SIGNAL_REQUEST_PAD] =
409 g_signal_new ("request-pad", G_TYPE_FROM_CLASS (klass),
410 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstEncodeBinClass,
411 request_pad), NULL, NULL, g_cclosure_marshal_generic,
412 GST_TYPE_PAD, 1, GST_TYPE_CAPS);
415 * GstEncodeBin::request-profile-pad
416 * @encodebin: a #GstEncodeBin instance
417 * @profilename: the name of a #GstEncodingProfile
419 * Use this method to request an unused sink request #GstPad from the profile
420 * @profilename. You must release the pad with
421 * gst_element_release_request_pad() when you are done with it.
423 * Returns: A compatible #GstPad, or %NULL if no compatible #GstPad could be
424 * created or is available.
426 gst_encode_bin_signals[SIGNAL_REQUEST_PROFILE_PAD] =
427 g_signal_new ("request-profile-pad", G_TYPE_FROM_CLASS (klass),
428 G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstEncodeBinClass,
429 request_profile_pad), NULL, NULL, g_cclosure_marshal_generic,
430 GST_TYPE_PAD, 1, G_TYPE_STRING);
432 klass->request_pad = gst_encode_bin_request_pad_signal;
433 klass->request_profile_pad = gst_encode_bin_request_profile_pad_signal;
435 gst_element_class_add_pad_template (gstelement_klass,
436 gst_static_pad_template_get (&muxer_src_template));
437 gst_element_class_add_pad_template (gstelement_klass,
438 gst_static_pad_template_get (&video_sink_template));
439 gst_element_class_add_pad_template (gstelement_klass,
440 gst_static_pad_template_get (&audio_sink_template));
441 /* gst_element_class_add_pad_template (gstelement_klass, */
442 /* gst_static_pad_template_get (&text_sink_template)); */
443 gst_element_class_add_pad_template (gstelement_klass,
444 gst_static_pad_template_get (&private_sink_template));
446 gstelement_klass->change_state =
447 GST_DEBUG_FUNCPTR (gst_encode_bin_change_state);
448 gstelement_klass->request_new_pad =
449 GST_DEBUG_FUNCPTR (gst_encode_bin_request_new_pad);
450 gstelement_klass->release_pad =
451 GST_DEBUG_FUNCPTR (gst_encode_bin_release_pad);
453 gst_element_class_set_static_metadata (gstelement_klass,
455 "Generic/Bin/Encoder",
456 "Convenience encoding/muxing element",
457 "Edward Hervey <edward.hervey@collabora.co.uk>");
461 gst_encode_bin_dispose (GObject * object)
463 GstEncodeBin *ebin = (GstEncodeBin *) object;
466 gst_plugin_feature_list_free (ebin->muxers);
468 if (ebin->formatters)
469 gst_plugin_feature_list_free (ebin->formatters);
472 gst_plugin_feature_list_free (ebin->encoders);
475 gst_plugin_feature_list_free (ebin->parsers);
477 gst_encode_bin_tear_down_profile (ebin);
479 if (ebin->raw_video_caps)
480 gst_caps_unref (ebin->raw_video_caps);
481 if (ebin->raw_audio_caps)
482 gst_caps_unref (ebin->raw_audio_caps);
483 /* if (ebin->raw_text_caps) */
484 /* gst_caps_unref (ebin->raw_text_caps); */
486 G_OBJECT_CLASS (gst_encode_bin_parent_class)->dispose (object);
490 gst_encode_bin_init (GstEncodeBin * encode_bin)
492 GstPadTemplate *tmpl;
495 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER,
498 encode_bin->formatters =
499 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_FORMATTER,
502 encode_bin->encoders =
503 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER,
506 encode_bin->parsers =
507 gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER,
510 encode_bin->raw_video_caps = gst_caps_from_string ("video/x-raw");
511 encode_bin->raw_audio_caps = gst_caps_from_string ("audio/x-raw");
512 /* encode_bin->raw_text_caps = */
513 /* gst_caps_from_string ("text/x-raw"); */
515 encode_bin->queue_buffers_max = DEFAULT_QUEUE_BUFFERS_MAX;
516 encode_bin->queue_bytes_max = DEFAULT_QUEUE_BYTES_MAX;
517 encode_bin->queue_time_max = DEFAULT_QUEUE_TIME_MAX;
518 encode_bin->tolerance = DEFAULT_AUDIO_JITTER_TOLERANCE;
519 encode_bin->avoid_reencoding = DEFAULT_AVOID_REENCODING;
520 encode_bin->flags = DEFAULT_FLAGS;
522 tmpl = gst_static_pad_template_get (&muxer_src_template);
523 encode_bin->srcpad = gst_ghost_pad_new_no_target_from_template ("src", tmpl);
524 gst_object_unref (tmpl);
525 gst_pad_set_active (encode_bin->srcpad, TRUE);
526 gst_element_add_pad (GST_ELEMENT_CAST (encode_bin), encode_bin->srcpad);
530 gst_encode_bin_set_property (GObject * object, guint prop_id,
531 const GValue * value, GParamSpec * pspec)
533 GstEncodeBin *ebin = (GstEncodeBin *) object;
537 gst_encode_bin_set_profile (ebin,
538 (GstEncodingProfile *) g_value_get_object (value));
540 case PROP_QUEUE_BUFFERS_MAX:
541 ebin->queue_buffers_max = g_value_get_uint (value);
543 case PROP_QUEUE_BYTES_MAX:
544 ebin->queue_bytes_max = g_value_get_uint (value);
546 case PROP_QUEUE_TIME_MAX:
547 ebin->queue_time_max = g_value_get_uint64 (value);
549 case PROP_AUDIO_JITTER_TOLERANCE:
550 ebin->tolerance = g_value_get_uint64 (value);
552 case PROP_AVOID_REENCODING:
553 ebin->avoid_reencoding = g_value_get_boolean (value);
556 ebin->flags = g_value_get_flags (value);
559 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
565 gst_encode_bin_get_property (GObject * object, guint prop_id,
566 GValue * value, GParamSpec * pspec)
568 GstEncodeBin *ebin = (GstEncodeBin *) object;
572 g_value_set_object (value, (GObject *) ebin->profile);
574 case PROP_QUEUE_BUFFERS_MAX:
575 g_value_set_uint (value, ebin->queue_buffers_max);
577 case PROP_QUEUE_BYTES_MAX:
578 g_value_set_uint (value, ebin->queue_bytes_max);
580 case PROP_QUEUE_TIME_MAX:
581 g_value_set_uint64 (value, ebin->queue_time_max);
583 case PROP_AUDIO_JITTER_TOLERANCE:
584 g_value_set_uint64 (value, ebin->tolerance);
586 case PROP_AVOID_REENCODING:
587 g_value_set_boolean (value, ebin->avoid_reencoding);
590 g_value_set_flags (value, ebin->flags);
593 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
598 static inline gboolean
599 are_raw_caps (const GstCaps * caps)
601 GstCaps *raw = gst_static_caps_get (&default_raw_caps);
603 if (gst_caps_can_intersect (caps, raw)) {
604 gst_caps_unref (raw);
607 gst_caps_unref (raw);
611 /* Returns the number of time a given stream profile is currently used
614 stream_profile_used_count (GstEncodeBin * ebin, GstEncodingProfile * sprof)
616 guint nbprofused = 0;
619 for (tmp = ebin->streams; tmp; tmp = tmp->next) {
620 StreamGroup *sgroup = (StreamGroup *) tmp->data;
622 if (sgroup->profile == sprof)
629 static inline GstEncodingProfile *
630 next_unused_stream_profile (GstEncodeBin * ebin, GType ptype,
631 const gchar * name, GstCaps * caps)
633 GST_DEBUG_OBJECT (ebin, "ptype:%s, caps:%" GST_PTR_FORMAT,
634 g_type_name (ptype), caps);
636 if (G_UNLIKELY (ptype == G_TYPE_NONE && caps != NULL)) {
637 /* Identify the profile type based on raw caps */
638 if (gst_caps_can_intersect (ebin->raw_video_caps, caps))
639 ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
640 else if (gst_caps_can_intersect (ebin->raw_audio_caps, caps))
641 ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
642 /* else if (gst_caps_can_intersect (ebin->raw_text_caps, caps)) */
643 /* ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
644 GST_DEBUG_OBJECT (ebin, "Detected profile type as being %s",
645 g_type_name (ptype));
648 if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
652 /* If we have a name, try to find a profile with the same name */
654 gst_encoding_container_profile_get_profiles
655 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
657 for (; tmp; tmp = tmp->next) {
658 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
659 const gchar *profilename = gst_encoding_profile_get_name (sprof);
661 if (profilename && !strcmp (name, profilename)) {
662 guint presence = gst_encoding_profile_get_presence (sprof);
663 GST_DEBUG ("Found profile matching the requested name");
666 || presence > stream_profile_used_count (ebin, sprof))
669 GST_WARNING ("Matching stream already used");
674 ("No profiles matching requested pad name, carrying on with normal stream matching");
678 gst_encoding_container_profile_get_profiles
679 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile)); tmp;
681 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
683 /* Pick an available Stream profile for which:
684 * * either it is of the compatible raw type,
685 * * OR we can pass it through directly without encoding
687 if (G_TYPE_FROM_INSTANCE (sprof) == ptype) {
688 guint presence = gst_encoding_profile_get_presence (sprof);
689 GST_DEBUG ("Found a stream profile with the same type");
691 || (presence > stream_profile_used_count (ebin, sprof)))
693 } else if (caps && ptype == G_TYPE_NONE) {
697 outcaps = gst_encoding_profile_get_input_caps (sprof);
698 GST_DEBUG ("Unknown stream, seeing if it's compatible with %"
699 GST_PTR_FORMAT, outcaps);
700 res = gst_caps_can_intersect (outcaps, caps);
701 gst_caps_unref (outcaps);
713 request_pad_for_stream (GstEncodeBin * encodebin, GType ptype,
714 const gchar * name, GstCaps * caps)
717 GstEncodingProfile *sprof;
719 GST_DEBUG_OBJECT (encodebin, "name:%s caps:%" GST_PTR_FORMAT, name, caps);
721 /* Figure out if we have a unused GstEncodingProfile we can use for
723 sprof = next_unused_stream_profile (encodebin, ptype, name, caps);
725 if (G_UNLIKELY (sprof == NULL))
726 goto no_stream_profile;
728 sgroup = _create_stream_group (encodebin, sprof, name, caps);
729 if (G_UNLIKELY (sgroup == NULL))
730 goto no_stream_group;
732 return sgroup->ghostpad;
736 GST_WARNING_OBJECT (encodebin, "Couldn't find a compatible stream profile");
742 GST_WARNING_OBJECT (encodebin, "Couldn't create a StreamGroup");
748 gst_encode_bin_request_new_pad (GstElement * element,
749 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
751 GstEncodeBin *ebin = (GstEncodeBin *) element;
754 GST_DEBUG_OBJECT (element, "templ:%s, name:%s", templ->name_template, name);
756 /* Identify the stream group (if name or caps have been provided) */
757 if (caps != NULL || name != NULL) {
758 res = request_pad_for_stream (ebin, G_TYPE_NONE, name, (GstCaps *) caps);
762 GType ptype = G_TYPE_NONE;
764 if (!strcmp (templ->name_template, "video_%u"))
765 ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
766 else if (!strcmp (templ->name_template, "audio_%u"))
767 ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
768 /* else if (!strcmp (templ->name_template, "text_%u")) */
769 /* ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
771 /* FIXME : Check uniqueness of pad */
772 /* FIXME : Check that the requested number is the last one, and if not,
773 * update the last_pad_id variable so that we don't create a pad with
774 * the same name/number in the future */
776 res = request_pad_for_stream (ebin, ptype, name, NULL);
783 gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin, GstCaps * caps)
785 GstPad *pad = request_pad_for_stream (encodebin, G_TYPE_NONE, NULL, caps);
787 return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL;
791 gst_encode_bin_request_profile_pad_signal (GstEncodeBin * encodebin,
792 const gchar * profilename)
795 request_pad_for_stream (encodebin, G_TYPE_NONE, profilename, NULL);
797 return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL;
800 static inline StreamGroup *
801 find_stream_group_from_pad (GstEncodeBin * ebin, GstPad * pad)
805 for (tmp = ebin->streams; tmp; tmp = tmp->next) {
806 StreamGroup *sgroup = (StreamGroup *) tmp->data;
807 if (G_UNLIKELY (sgroup->ghostpad == pad))
815 gst_encode_bin_release_pad (GstElement * element, GstPad * pad)
817 GstEncodeBin *ebin = (GstEncodeBin *) element;
820 /* Find the associated StreamGroup */
822 sgroup = find_stream_group_from_pad (ebin, pad);
823 if (G_UNLIKELY (sgroup == NULL))
824 goto no_stream_group;
826 /* Release objects/data associated with the StreamGroup */
827 stream_group_remove (ebin, sgroup);
833 GST_WARNING_OBJECT (ebin, "Couldn't find corresponding StreamGroup");
838 /* Create a parser for the given stream profile */
839 static inline GstElement *
840 _get_parser (GstEncodeBin * ebin, GstEncodingProfile * sprof)
842 GList *parsers1, *parsers, *tmp;
843 GstElement *parser = NULL;
844 GstElementFactory *parserfact = NULL;
847 format = gst_encoding_profile_get_format (sprof);
849 GST_DEBUG ("Getting list of parsers for format %" GST_PTR_FORMAT, format);
851 /* FIXME : requesting twice the parsers twice is a bit ugly, we should
852 * have a method to request on more than one condition */
854 gst_element_factory_list_filter (ebin->parsers, format,
857 gst_element_factory_list_filter (parsers1, format, GST_PAD_SINK, FALSE);
858 gst_plugin_feature_list_free (parsers1);
860 if (G_UNLIKELY (parsers == NULL)) {
861 GST_DEBUG ("Couldn't find any compatible parsers");
865 for (tmp = parsers; tmp; tmp = tmp->next) {
866 /* FIXME : We're only picking the first one so far */
867 /* FIXME : signal the user if he wants this */
868 parserfact = (GstElementFactory *) tmp->data;
873 parser = gst_element_factory_create (parserfact, NULL);
875 gst_plugin_feature_list_free (parsers);
879 gst_caps_unref (format);
885 _create_element_and_set_preset (GstElementFactory * factory,
886 const gchar * preset, const gchar * name, const gchar * preset_name)
888 GstElement *res = NULL;
890 GST_DEBUG ("Creating element from factory %s (preset factory name: %s"
891 " preset name: %s)", GST_OBJECT_NAME (factory), preset, preset_name);
893 res = gst_element_factory_create (factory, name);
895 if (preset && GST_IS_PRESET (res)) {
896 if (preset_name == NULL ||
897 g_strcmp0 (GST_OBJECT_NAME (factory), preset_name) == 0) {
899 if (!gst_preset_load_preset (GST_PRESET (res), preset)) {
900 GST_WARNING ("Couldn't set preset [%s] on element [%s]",
901 preset, GST_OBJECT_NAME (factory));
902 gst_object_unref (res);
906 GST_DEBUG ("Using a preset with no preset name, making use of the"
907 " proper element without setting any property");
909 } else if (preset_name && g_strcmp0 (GST_OBJECT_NAME (factory), preset_name)) {
910 gst_object_unref (res);
913 /* Else we keep it */
918 /* Create the encoder for the given stream profile */
919 static inline GstElement *
920 _get_encoder (GstEncodeBin * ebin, GstEncodingProfile * sprof)
922 GList *encoders, *tmp;
923 GstElement *encoder = NULL;
924 GstElementFactory *encoderfact = NULL;
926 const gchar *preset, *preset_name;
928 format = gst_encoding_profile_get_format (sprof);
929 preset = gst_encoding_profile_get_preset (sprof);
930 preset_name = gst_encoding_profile_get_preset_name (sprof);
932 GST_DEBUG ("Getting list of encoders for format %" GST_PTR_FORMAT, format);
934 /* If stream caps are raw, return identity */
935 if (G_UNLIKELY (are_raw_caps (format))) {
936 GST_DEBUG ("Stream format is raw, returning identity as the encoder");
937 encoder = gst_element_factory_make ("identity", NULL);
942 gst_element_factory_list_filter (ebin->encoders, format,
945 if (G_UNLIKELY (encoders == NULL)) {
946 GST_DEBUG ("Couldn't find any compatible encoders");
950 for (tmp = encoders; tmp; tmp = tmp->next) {
951 encoderfact = (GstElementFactory *) tmp->data;
952 if ((encoder = _create_element_and_set_preset (encoderfact, preset,
957 gst_plugin_feature_list_free (encoders);
961 gst_caps_unref (format);
967 local_element_request_pad (GstElement * element, GstPadTemplate * templ,
968 const gchar * name, const GstCaps * caps)
970 GstPad *newpad = NULL;
971 GstElementClass *oclass;
973 oclass = GST_ELEMENT_GET_CLASS (element);
975 if (oclass->request_new_pad)
976 newpad = (oclass->request_new_pad) (element, templ, name, caps);
979 gst_object_ref (newpad);
985 gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
988 GstPadPresence presence;
990 /* If this function is ever exported, we need check the validity of `element'
991 * and `templ', and to make sure the template actually belongs to the
994 presence = GST_PAD_TEMPLATE_PRESENCE (templ);
998 case GST_PAD_SOMETIMES:
999 ret = gst_element_get_static_pad (element, templ->name_template);
1000 if (!ret && presence == GST_PAD_ALWAYS)
1002 ("Element %s has an ALWAYS template %s, but no pad of the same name",
1003 GST_OBJECT_NAME (element), templ->name_template);
1006 case GST_PAD_REQUEST:
1007 ret = gst_element_request_pad (element, templ, NULL, NULL);
1014 /* FIXME : Improve algorithm for finding compatible muxer sink pad */
1015 static inline GstPad *
1016 get_compatible_muxer_sink_pad (GstEncodeBin * ebin, GstElement * encoder,
1020 GstPadTemplate *srctempl = NULL;
1021 GstPadTemplate *sinktempl;
1025 srcpad = gst_element_get_static_pad (encoder, "src");
1027 srctempl = gst_pad_get_pad_template (srcpad);
1029 GST_DEBUG_OBJECT (ebin,
1030 "Attempting to find pad from muxer %s compatible with %s:%s",
1031 GST_ELEMENT_NAME (ebin->muxer), GST_DEBUG_PAD_NAME (srcpad));
1033 gst_object_unref (srcpad);
1034 sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
1035 gst_object_unref (srctempl);
1038 gst_pad_template_new ("whatever", GST_PAD_SRC, GST_PAD_ALWAYS,
1040 g_assert (srctempl != NULL);
1041 sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
1042 g_object_unref (srctempl);
1045 if (G_UNLIKELY (sinktempl == NULL))
1048 sinkpad = gst_element_get_pad_from_template (ebin->muxer, sinktempl);
1054 GST_WARNING_OBJECT (ebin, "No compatible pad available on muxer");
1060 _has_class (GstElement * element, const gchar * classname)
1062 GstElementClass *klass;
1065 klass = GST_ELEMENT_GET_CLASS (element);
1066 value = gst_element_class_get_metadata (klass, GST_ELEMENT_METADATA_KLASS);
1070 return strstr (value, classname) != NULL;
1074 _profile_restriction_caps_cb (GstEncodingProfile * profile,
1075 GParamSpec * arg G_GNUC_UNUSED, StreamGroup * group)
1077 GstCaps *restriction = gst_encoding_profile_get_restriction (profile);
1079 g_object_set (group->capsfilter, "caps", restriction, NULL);
1083 _outfilter_caps_set_cb (GstPad * outfilter_sinkpad,
1084 GParamSpec * arg G_GNUC_UNUSED, StreamGroup * group)
1088 g_object_get (outfilter_sinkpad, "caps", &caps, NULL);
1089 GST_INFO_OBJECT (group->ebin, "Forcing caps to %" GST_PTR_FORMAT, caps);
1090 g_object_set (group->outfilter, "caps", caps, NULL);
1091 g_signal_handler_disconnect (outfilter_sinkpad, group->outputfilter_caps_sid);
1092 group->outputfilter_caps_sid = 0;
1096 _set_group_caps_format (StreamGroup * sgroup, GstEncodingProfile * prof,
1099 g_object_set (sgroup->outfilter, "caps", format, NULL);
1101 if (!gst_encoding_profile_get_allow_dynamic_output (prof)) {
1102 if (!sgroup->outputfilter_caps_sid) {
1103 sgroup->outputfilter_caps_sid =
1104 g_signal_connect (sgroup->outfilter->sinkpads->data,
1105 "notify::caps", G_CALLBACK (_outfilter_caps_set_cb), sgroup);
1111 _post_missing_plugin_message (GstEncodeBin * ebin, GstEncodingProfile * prof)
1114 format = gst_encoding_profile_get_format (prof);
1116 GST_ERROR_OBJECT (ebin, "Couldn't create encoder for format %" GST_PTR_FORMAT,
1118 /* missing plugin support */
1119 gst_element_post_message (GST_ELEMENT_CAST (ebin),
1120 gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format));
1121 GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL),
1122 ("Couldn't create encoder for format %" GST_PTR_FORMAT, format));
1124 gst_caps_unref (format);
1127 static GstPadProbeReturn
1128 _missing_plugin_probe (GstPad * pad, GstPadProbeInfo * info, gpointer udata)
1130 StreamGroup *sgroup = udata;
1131 GstEncodeBin *ebin = sgroup->ebin;
1133 _post_missing_plugin_message (ebin, sgroup->profile);
1135 return GST_PAD_PROBE_OK;
1139 _set_up_fake_encoder_pad_probe (GstEncodeBin * ebin, StreamGroup * sgroup)
1141 GstPad *pad = gst_element_get_static_pad (sgroup->fakesink, "sink");
1143 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, _missing_plugin_probe,
1146 gst_object_unref (pad);
1149 /* FIXME : Add handling of streams that don't require conversion elements */
1151 * Create the elements, StreamGroup, add the sink pad, link it to the muxer
1153 * sinkpadname: If non-NULL, that name will be assigned to the sink ghost pad
1154 * sinkcaps: If non-NULL will be used to figure out how to setup the group */
1155 static StreamGroup *
1156 _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
1157 const gchar * sinkpadname, GstCaps * sinkcaps)
1159 StreamGroup *sgroup = NULL;
1160 GstPad *sinkpad, *srcpad, *muxerpad = NULL;
1161 /* Element we will link to the encoder */
1162 GstElement *last = NULL;
1163 GstElement *encoder = NULL;
1164 GList *tmp, *tosync = NULL;
1165 GstCaps *format, *restriction;
1166 const gchar *missing_element_name;
1168 format = gst_encoding_profile_get_format (sprof);
1169 restriction = gst_encoding_profile_get_restriction (sprof);
1171 GST_DEBUG ("Creating group. format %" GST_PTR_FORMAT ", for caps %"
1172 GST_PTR_FORMAT, format, sinkcaps);
1173 GST_DEBUG ("avoid_reencoding:%d", ebin->avoid_reencoding);
1175 sgroup = g_slice_new0 (StreamGroup);
1176 sgroup->ebin = ebin;
1177 sgroup->profile = sprof;
1179 /* NOTE for people reading this code:
1181 * We construct the group starting by the furthest downstream element
1182 * and making our way up adding/syncing/linking as we go.
1184 * There are two parallel paths:
1185 * * One for raw data which goes through converters and encoders
1186 * * One for already encoded data
1190 * If we are handling a container profile, figure out if the muxer has a
1191 * sinkpad compatible with the selected profile */
1193 muxerpad = get_compatible_muxer_sink_pad (ebin, NULL, format);
1194 if (G_UNLIKELY (muxerpad == NULL))
1200 * We only use a 1buffer long queue here, the actual queueing will be done
1201 * in the input queue */
1202 last = sgroup->outqueue = gst_element_factory_make ("queue", NULL);
1203 g_object_set (sgroup->outqueue, "max-size-buffers", (guint32) 1,
1204 "max-size-bytes", (guint32) 0, "max-size-time", (guint64) 0,
1205 "silent", TRUE, NULL);
1207 gst_bin_add (GST_BIN (ebin), sgroup->outqueue);
1208 tosync = g_list_append (tosync, sgroup->outqueue);
1209 srcpad = gst_element_get_static_pad (sgroup->outqueue, "src");
1211 if (G_UNLIKELY (fast_pad_link (srcpad, muxerpad) != GST_PAD_LINK_OK)) {
1212 goto muxer_link_failure;
1214 gst_object_unref (muxerpad);
1216 gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), srcpad);
1218 gst_object_unref (srcpad);
1220 /* Check if we need a formatter
1221 * If we have no muxer or
1222 * if the muxer isn't a formatter and doesn't implement the tagsetter interface
1224 if (!ebin->muxer || (!GST_IS_TAG_SETTER (ebin->muxer)
1225 && !_has_class (ebin->muxer, "Formatter"))) {
1226 sgroup->formatter = _get_formatter (ebin, sprof);
1227 if (sgroup->formatter) {
1228 GST_DEBUG ("Adding formatter for %" GST_PTR_FORMAT, format);
1230 gst_bin_add (GST_BIN (ebin), sgroup->formatter);
1231 tosync = g_list_append (tosync, sgroup->formatter);
1232 if (G_UNLIKELY (!fast_element_link (sgroup->formatter, last)))
1233 goto formatter_link_failure;
1234 last = sgroup->formatter;
1239 /* Output capsfilter
1240 * This will receive the format caps from the streamprofile */
1241 GST_DEBUG ("Adding output capsfilter for %" GST_PTR_FORMAT, format);
1242 sgroup->outfilter = gst_element_factory_make ("capsfilter", NULL);
1243 _set_group_caps_format (sgroup, sprof, format);
1245 gst_bin_add (GST_BIN (ebin), sgroup->outfilter);
1246 tosync = g_list_append (tosync, sgroup->outfilter);
1247 if (G_UNLIKELY (!fast_element_link (sgroup->outfilter, last)))
1248 goto outfilter_link_failure;
1249 last = sgroup->outfilter;
1252 sgroup->parser = _get_parser (ebin, sprof);
1254 if (sgroup->parser != NULL) {
1255 GST_DEBUG ("Got a parser %s", GST_ELEMENT_NAME (sgroup->parser));
1256 gst_bin_add (GST_BIN (ebin), sgroup->parser);
1257 tosync = g_list_append (tosync, sgroup->parser);
1258 if (G_UNLIKELY (!gst_element_link (sgroup->parser, last)))
1259 goto parser_link_failure;
1260 last = sgroup->parser;
1263 /* Stream combiner */
1264 sgroup->combiner = g_object_new (GST_TYPE_STREAM_COMBINER, NULL);
1266 gst_bin_add (GST_BIN (ebin), sgroup->combiner);
1267 tosync = g_list_append (tosync, sgroup->combiner);
1268 if (G_UNLIKELY (!fast_element_link (sgroup->combiner, last)))
1269 goto combiner_link_failure;
1272 /* Stream splitter */
1273 sgroup->splitter = g_object_new (GST_TYPE_STREAM_SPLITTER, NULL);
1275 gst_bin_add (GST_BIN (ebin), sgroup->splitter);
1276 tosync = g_list_append (tosync, sgroup->splitter);
1279 * FIXME : figure out what max-size to use for the input queue */
1280 sgroup->inqueue = gst_element_factory_make ("queue", NULL);
1281 g_object_set (sgroup->inqueue, "max-size-buffers",
1282 (guint32) ebin->queue_buffers_max, "max-size-bytes",
1283 (guint32) ebin->queue_bytes_max, "max-size-time",
1284 (guint64) ebin->queue_time_max, "silent", TRUE, NULL);
1286 gst_bin_add (GST_BIN (ebin), sgroup->inqueue);
1287 tosync = g_list_append (tosync, sgroup->inqueue);
1288 if (G_UNLIKELY (!fast_element_link (sgroup->inqueue, sgroup->splitter)))
1289 goto splitter_link_failure;
1291 /* Expose input queue sink pad as ghostpad */
1292 sinkpad = gst_element_get_static_pad (sgroup->inqueue, "sink");
1293 if (sinkpadname == NULL) {
1295 g_strdup_printf ("%s_%u", gst_encoding_profile_get_type_nick (sprof),
1296 ebin->last_pad_id++);
1297 GST_DEBUG ("Adding ghost pad %s", pname);
1298 sgroup->ghostpad = gst_ghost_pad_new (pname, sinkpad);
1301 sgroup->ghostpad = gst_ghost_pad_new (sinkpadname, sinkpad);
1302 gst_object_unref (sinkpad);
1305 /* Path 1 : Already-encoded data */
1307 local_element_request_pad (sgroup->combiner, NULL, "passthroughsink",
1309 if (G_UNLIKELY (sinkpad == NULL))
1310 goto no_combiner_sinkpad;
1312 if (ebin->avoid_reencoding) {
1315 GST_DEBUG ("Asked to use Smart Encoder");
1316 sgroup->smartencoder = g_object_new (GST_TYPE_SMART_ENCODER, NULL);
1318 /* Check if stream format is compatible */
1319 srcpad = gst_element_get_static_pad (sgroup->smartencoder, "src");
1320 tmpcaps = gst_pad_query_caps (srcpad, NULL);
1321 if (!gst_caps_can_intersect (tmpcaps, format)) {
1322 GST_DEBUG ("We don't have a smart encoder for the stream format");
1323 gst_object_unref (sgroup->smartencoder);
1324 sgroup->smartencoder = NULL;
1326 gst_bin_add ((GstBin *) ebin, sgroup->smartencoder);
1327 fast_pad_link (srcpad, sinkpad);
1328 tosync = g_list_append (tosync, sgroup->smartencoder);
1329 sinkpad = gst_element_get_static_pad (sgroup->smartencoder, "sink");
1331 gst_caps_unref (tmpcaps);
1332 g_object_unref (srcpad);
1336 local_element_request_pad (sgroup->splitter, NULL, "passthroughsrc",
1338 if (G_UNLIKELY (srcpad == NULL))
1339 goto no_splitter_srcpad;
1341 /* Go straight to splitter */
1342 if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1343 goto passthrough_link_failure;
1344 g_object_unref (sinkpad);
1345 g_object_unref (srcpad);
1348 /* Path 2 : Conversion / Encoding */
1350 /* 1. Create the encoder */
1351 GST_LOG ("Adding encoder");
1352 sgroup->encoder = _get_encoder (ebin, sprof);
1353 if (sgroup->encoder != NULL) {
1354 gst_bin_add ((GstBin *) ebin, sgroup->encoder);
1355 tosync = g_list_append (tosync, sgroup->encoder);
1358 local_element_request_pad (sgroup->combiner, NULL, "encodingsink",
1360 if (G_UNLIKELY (sinkpad == NULL))
1361 goto no_combiner_sinkpad;
1362 srcpad = gst_element_get_static_pad (sgroup->encoder, "src");
1363 if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1364 goto encoder_link_failure;
1365 g_object_unref (sinkpad);
1366 g_object_unref (srcpad);
1367 } else if (gst_encoding_profile_get_preset (sgroup->profile)
1368 || gst_encoding_profile_get_preset_name (sgroup->profile)) {
1369 _post_missing_plugin_message (ebin, sprof);
1372 /* passthrough can still work, if we discover that *
1373 * encoding is required we post a missing plugin message */
1377 /* 3. Create the conversion/restriction elements */
1378 /* 3.1. capsfilter */
1379 GST_LOG ("Adding capsfilter for restriction caps : %" GST_PTR_FORMAT,
1382 last = sgroup->capsfilter = gst_element_factory_make ("capsfilter", NULL);
1383 if (restriction && !gst_caps_is_any (restriction))
1384 g_object_set (sgroup->capsfilter, "caps", restriction, NULL);
1385 gst_bin_add ((GstBin *) ebin, sgroup->capsfilter);
1386 tosync = g_list_append (tosync, sgroup->capsfilter);
1387 if (sgroup->encoder == NULL) {
1388 /* no encoder available but it might be possible to just do passthrough, so
1389 * let's just set up a fake pad to detect that encoding was attempted and
1390 * if so it posts the missing plugin message */
1391 sgroup->fakesink = gst_element_factory_make ("fakesink", NULL);
1392 g_object_set (sgroup->fakesink, "async", FALSE, NULL);
1393 gst_bin_add (GST_BIN_CAST (ebin), sgroup->fakesink);
1394 tosync = g_list_append (tosync, sgroup->fakesink);
1395 encoder = sgroup->fakesink;
1397 _set_up_fake_encoder_pad_probe (ebin, sgroup);
1399 encoder = sgroup->encoder;
1401 fast_element_link (sgroup->capsfilter, encoder);
1402 sgroup->restriction_sid = g_signal_connect (sprof, "notify::restriction-caps",
1403 G_CALLBACK (_profile_restriction_caps_cb), sgroup);
1405 /* 3.2. restriction elements */
1406 /* FIXME : Once we have properties for specific converters, use those */
1407 if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
1408 const gboolean native_video =
1409 ! !(ebin->flags & GST_ENCODEBIN_FLAG_NO_VIDEO_CONVERSION);
1410 GstElement *cspace = NULL, *scale, *vrate, *cspace2 = NULL;
1412 GST_LOG ("Adding conversion elements for video stream");
1414 if (!native_video) {
1415 cspace = gst_element_factory_make ("videoconvert", NULL);
1416 scale = gst_element_factory_make ("videoscale", NULL);
1418 missing_element_name = "videoscale";
1419 goto missing_element;
1421 /* 4-tap scaling and black borders */
1422 g_object_set (scale, "method", 2, "add-borders", TRUE, NULL);
1423 cspace2 = gst_element_factory_make ("videoconvert", NULL);
1425 if (!cspace || !cspace2) {
1426 missing_element_name = "videoconvert";
1427 goto missing_element;
1430 gst_bin_add_many ((GstBin *) ebin, cspace, scale, cspace2, NULL);
1431 tosync = g_list_append (tosync, cspace);
1432 tosync = g_list_append (tosync, scale);
1433 tosync = g_list_append (tosync, cspace2);
1435 sgroup->converters = g_list_prepend (sgroup->converters, cspace);
1436 sgroup->converters = g_list_prepend (sgroup->converters, scale);
1437 sgroup->converters = g_list_prepend (sgroup->converters, cspace2);
1439 if (!fast_element_link (cspace, scale) ||
1440 !fast_element_link (scale, cspace2))
1441 goto converter_link_failure;
1444 if (!gst_encoding_video_profile_get_variableframerate
1445 (GST_ENCODING_VIDEO_PROFILE (sprof))) {
1446 vrate = gst_element_factory_make ("videorate", NULL);
1448 missing_element_name = "videorate";
1449 goto missing_element;
1452 gst_bin_add ((GstBin *) ebin, vrate);
1453 tosync = g_list_prepend (tosync, vrate);
1454 sgroup->converters = g_list_prepend (sgroup->converters, vrate);
1456 if ((!native_video && !fast_element_link (cspace2, vrate))
1457 || !fast_element_link (vrate, last))
1458 goto converter_link_failure;
1464 } else if (!native_video) {
1465 if (!fast_element_link (cspace2, last))
1466 goto converter_link_failure;
1470 } else if (GST_IS_ENCODING_AUDIO_PROFILE (sprof)
1471 && !(ebin->flags & GST_ENCODEBIN_FLAG_NO_AUDIO_CONVERSION)) {
1472 GstElement *aconv, *ares, *arate, *aconv2;
1474 GST_LOG ("Adding conversion elements for audio stream");
1476 arate = gst_element_factory_make ("audiorate", NULL);
1477 g_object_set (arate, "tolerance", (guint64) ebin->tolerance, NULL);
1479 missing_element_name = "audiorate";
1480 goto missing_element;
1482 aconv = gst_element_factory_make ("audioconvert", NULL);
1483 aconv2 = gst_element_factory_make ("audioconvert", NULL);
1484 ares = gst_element_factory_make ("audioresample", NULL);
1485 if (!aconv || !aconv2) {
1486 missing_element_name = "audioconvert";
1487 goto missing_element;
1490 missing_element_name = "audioresample";
1491 goto missing_element;
1494 gst_bin_add_many ((GstBin *) ebin, arate, aconv, ares, aconv2, NULL);
1495 tosync = g_list_append (tosync, arate);
1496 tosync = g_list_append (tosync, aconv);
1497 tosync = g_list_append (tosync, ares);
1498 tosync = g_list_append (tosync, aconv2);
1499 if (!fast_element_link (arate, aconv) ||
1500 !fast_element_link (aconv, ares) ||
1501 !fast_element_link (ares, aconv2) || !fast_element_link (aconv2, last))
1502 goto converter_link_failure;
1504 sgroup->converters = g_list_prepend (sgroup->converters, arate);
1505 sgroup->converters = g_list_prepend (sgroup->converters, aconv);
1506 sgroup->converters = g_list_prepend (sgroup->converters, ares);
1507 sgroup->converters = g_list_prepend (sgroup->converters, aconv2);
1512 /* Link to stream splitter */
1513 sinkpad = gst_element_get_static_pad (last, "sink");
1515 local_element_request_pad (sgroup->splitter, NULL, "encodingsrc", NULL);
1516 if (G_UNLIKELY (srcpad == NULL))
1517 goto no_splitter_srcpad;
1518 if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1519 goto splitter_encoding_failure;
1520 g_object_unref (sinkpad);
1521 g_object_unref (srcpad);
1523 /* End of Stream 2 setup */
1525 /* Sync all elements to parent state */
1526 for (tmp = tosync; tmp; tmp = tmp->next)
1527 gst_element_sync_state_with_parent ((GstElement *) tmp->data);
1528 g_list_free (tosync);
1531 GST_DEBUG ("Adding ghostpad %s:%s", GST_DEBUG_PAD_NAME (sgroup->ghostpad));
1532 gst_pad_set_active (sgroup->ghostpad, TRUE);
1533 gst_element_add_pad ((GstElement *) ebin, sgroup->ghostpad);
1535 /* Add StreamGroup to our list of streams */
1538 ("Done creating elements, adding StreamGroup to our controlled stream list");
1540 ebin->streams = g_list_prepend (ebin->streams, sgroup);
1543 gst_caps_unref (format);
1545 gst_caps_unref (restriction);
1549 splitter_encoding_failure:
1550 GST_ERROR_OBJECT (ebin, "Error linking splitter to encoding stream");
1554 GST_ERROR_OBJECT (ebin,
1555 "Couldn't find a compatible muxer pad to link encoder to");
1559 gst_element_post_message (GST_ELEMENT_CAST (ebin),
1560 gst_missing_element_message_new (GST_ELEMENT_CAST (ebin),
1561 missing_element_name));
1562 GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN,
1563 (_("Missing element '%s' - check your GStreamer installation."),
1564 missing_element_name), (NULL));
1567 encoder_link_failure:
1568 GST_ERROR_OBJECT (ebin, "Failed to link the encoder");
1572 GST_ERROR_OBJECT (ebin, "Couldn't link encoder to muxer");
1575 formatter_link_failure:
1576 GST_ERROR_OBJECT (ebin, "Couldn't link output filter to output queue");
1579 outfilter_link_failure:
1580 GST_ERROR_OBJECT (ebin,
1581 "Couldn't link output filter to output queue/formatter");
1584 passthrough_link_failure:
1585 GST_ERROR_OBJECT (ebin, "Failed linking splitter in passthrough mode");
1589 GST_ERROR_OBJECT (ebin, "Couldn't get a source pad from the splitter");
1592 no_combiner_sinkpad:
1593 GST_ERROR_OBJECT (ebin, "Couldn't get a sink pad from the combiner");
1596 splitter_link_failure:
1597 GST_ERROR_OBJECT (ebin, "Failure linking to the splitter");
1600 combiner_link_failure:
1601 GST_ERROR_OBJECT (ebin, "Failure linking to the combiner");
1604 parser_link_failure:
1605 GST_ERROR_OBJECT (ebin, "Failure linking the parser");
1608 converter_link_failure:
1609 GST_ERROR_OBJECT (ebin, "Failure linking the video converters");
1613 /* FIXME : Actually properly cleanup everything */
1615 gst_caps_unref (format);
1617 gst_caps_unref (restriction);
1618 stream_group_free (ebin, sgroup);
1619 g_list_free (tosync);
1624 _gst_caps_match_foreach (GQuark field_id, const GValue * value, gpointer data)
1626 GstStructure *structure = data;
1627 const GValue *other_value = gst_structure_id_get_value (structure, field_id);
1629 if (G_UNLIKELY (other_value == NULL))
1631 if (gst_value_compare (value, other_value) == GST_VALUE_EQUAL) {
1639 * checks that there is at least one structure on caps_a that has
1640 * all its fields exactly the same as one structure on caps_b
1643 _gst_caps_match (const GstCaps * caps_a, const GstCaps * caps_b)
1646 gboolean res = FALSE;
1648 for (i = 0; i < gst_caps_get_size (caps_a); i++) {
1649 GstStructure *structure_a = gst_caps_get_structure (caps_a, i);
1650 for (j = 0; j < gst_caps_get_size (caps_b); j++) {
1651 GstStructure *structure_b = gst_caps_get_structure (caps_b, j);
1653 res = gst_structure_foreach (structure_a, _gst_caps_match_foreach,
1664 _factory_can_handle_caps (GstElementFactory * factory, const GstCaps * caps,
1665 GstPadDirection dir, gboolean exact)
1667 const GList *templates;
1669 templates = gst_element_factory_get_static_pad_templates (factory);
1671 GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
1673 if (template->direction == dir) {
1674 GstCaps *tmp = gst_static_caps_get (&template->static_caps);
1676 if ((exact && _gst_caps_match (caps, tmp)) ||
1677 (!exact && gst_caps_can_intersect (tmp, caps))) {
1678 gst_caps_unref (tmp);
1681 gst_caps_unref (tmp);
1683 templates = g_list_next (templates);
1689 static inline GstElement *
1690 _get_formatter (GstEncodeBin * ebin, GstEncodingProfile * sprof)
1692 GList *formatters, *tmpfmtr;
1693 GstElement *formatter = NULL;
1694 GstElementFactory *formatterfact = NULL;
1696 const gchar *preset, *preset_name;
1698 format = gst_encoding_profile_get_format (sprof);
1699 preset = gst_encoding_profile_get_preset (sprof);
1700 preset_name = gst_encoding_profile_get_preset_name (sprof);
1702 GST_DEBUG ("Getting list of formatters for format %" GST_PTR_FORMAT, format);
1705 gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
1708 if (formatters == NULL)
1711 /* FIXME : signal the user if he wants this */
1712 for (tmpfmtr = formatters; tmpfmtr; tmpfmtr = tmpfmtr->next) {
1713 formatterfact = (GstElementFactory *) tmpfmtr->data;
1715 GST_DEBUG_OBJECT (ebin, "Trying formatter %s",
1716 GST_OBJECT_NAME (formatterfact));
1719 _create_element_and_set_preset (formatterfact, preset,
1720 NULL, preset_name)))
1724 gst_plugin_feature_list_free (formatters);
1728 gst_caps_unref (format);
1733 compare_elements (gconstpointer a, gconstpointer b, gpointer udata)
1735 GstCaps *caps = udata;
1736 GstElementFactory *fac_a = (GstElementFactory *) a;
1737 GstElementFactory *fac_b = (GstElementFactory *) b;
1739 /* FIXME not quite sure this is the best algorithm to order the elements
1740 * Some caps similarity comparison algorithm would fit better than going
1741 * boolean (equals/not equals).
1743 gboolean equals_a = _factory_can_handle_caps (fac_a, caps, GST_PAD_SRC, TRUE);
1744 gboolean equals_b = _factory_can_handle_caps (fac_b, caps, GST_PAD_SRC, TRUE);
1746 if (equals_a == equals_b) {
1747 return gst_plugin_feature_get_rank ((GstPluginFeature *) fac_b) -
1748 gst_plugin_feature_get_rank ((GstPluginFeature *) fac_a);
1749 } else if (equals_a) {
1751 } else if (equals_b) {
1757 static inline GstElement *
1758 _get_muxer (GstEncodeBin * ebin)
1760 GList *muxers, *formatters, *tmpmux;
1761 GstElement *muxer = NULL;
1762 GstElementFactory *muxerfact = NULL;
1765 const gchar *preset, *preset_name;
1767 format = gst_encoding_profile_get_format (ebin->profile);
1768 preset = gst_encoding_profile_get_preset (ebin->profile);
1769 preset_name = gst_encoding_profile_get_preset_name (ebin->profile);
1771 GST_DEBUG ("Getting list of muxers for format %" GST_PTR_FORMAT, format);
1774 gst_element_factory_list_filter (ebin->muxers, format, GST_PAD_SRC, TRUE);
1777 gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
1780 muxers = g_list_sort_with_data (muxers, compare_elements, (gpointer) format);
1782 g_list_sort_with_data (formatters, compare_elements, (gpointer) format);
1784 muxers = g_list_concat (muxers, formatters);
1789 /* FIXME : signal the user if he wants this */
1790 for (tmpmux = muxers; tmpmux; tmpmux = tmpmux->next) {
1791 gboolean cansinkstreams = TRUE;
1792 const GList *profiles =
1793 gst_encoding_container_profile_get_profiles
1794 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
1796 muxerfact = (GstElementFactory *) tmpmux->data;
1798 GST_DEBUG ("Trying muxer %s", GST_OBJECT_NAME (muxerfact));
1800 /* See if the muxer can sink all of our stream profile caps */
1801 for (tmp = profiles; tmp; tmp = tmp->next) {
1802 GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
1803 GstCaps *sformat = gst_encoding_profile_get_format (sprof);
1805 if (!_factory_can_handle_caps (muxerfact, sformat, GST_PAD_SINK, FALSE)) {
1806 GST_DEBUG ("Skipping muxer because it can't sink caps %"
1807 GST_PTR_FORMAT, sformat);
1808 cansinkstreams = FALSE;
1810 gst_caps_unref (sformat);
1814 gst_caps_unref (sformat);
1817 /* Only use a muxer than can use all streams and than can accept the
1818 * preset (which may be present or not) */
1819 if (cansinkstreams && (muxer =
1820 _create_element_and_set_preset (muxerfact, preset, "muxer",
1825 gst_plugin_feature_list_free (muxers);
1829 gst_caps_unref (format);
1834 create_elements_and_pads (GstEncodeBin * ebin)
1836 gboolean ret = TRUE;
1837 GstElement *muxer = NULL;
1839 const GList *tmp, *profiles;
1840 GstEncodingProfile *sprof;
1842 GST_DEBUG ("Current profile : %s",
1843 gst_encoding_profile_get_name (ebin->profile));
1845 if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
1846 /* 1. Get the compatible muxer */
1847 muxer = _get_muxer (ebin);
1848 if (G_UNLIKELY (muxer == NULL))
1851 /* Record the muxer */
1852 ebin->muxer = muxer;
1853 gst_bin_add ((GstBin *) ebin, muxer);
1855 /* 2. Ghost the muxer source pad */
1857 /* FIXME : We should figure out if it's a static/request/dyamic pad,
1858 * but for the time being let's assume it's a static pad :) */
1859 muxerpad = gst_element_get_static_pad (muxer, "src");
1860 if (G_UNLIKELY (muxerpad == NULL))
1863 if (!gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), muxerpad))
1864 goto no_muxer_ghost_pad;
1866 gst_object_unref (muxerpad);
1867 /* 3. Activate fixed presence streams */
1869 gst_encoding_container_profile_get_profiles
1870 (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
1871 for (tmp = profiles; tmp; tmp = tmp->next) {
1872 sprof = (GstEncodingProfile *) tmp->data;
1874 GST_DEBUG ("Trying stream profile with presence %d",
1875 gst_encoding_profile_get_presence (sprof));
1877 if (gst_encoding_profile_get_presence (sprof) != 0) {
1878 if (G_UNLIKELY (_create_stream_group (ebin, sprof, NULL, NULL) == NULL))
1882 gst_element_sync_state_with_parent (muxer);
1884 if (G_UNLIKELY (_create_stream_group (ebin, ebin->profile, NULL,
1893 GstCaps *format = gst_encoding_profile_get_format (ebin->profile);
1895 GST_WARNING ("No available muxer for %" GST_PTR_FORMAT, format);
1896 /* missing plugin support */
1897 gst_element_post_message (GST_ELEMENT_CAST (ebin),
1898 gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format));
1899 GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL),
1900 ("No available muxer for format %" GST_PTR_FORMAT, format));
1902 gst_caps_unref (format);
1908 GST_WARNING ("Can't get source pad from muxer (%s)",
1909 GST_ELEMENT_NAME (muxer));
1910 gst_bin_remove (GST_BIN (ebin), muxer);
1916 GST_WARNING ("Couldn't set %s:%s as source ghostpad target",
1917 GST_DEBUG_PAD_NAME (muxerpad));
1918 gst_bin_remove (GST_BIN (ebin), muxer);
1919 gst_object_unref (muxerpad);
1925 GST_WARNING ("Could not create Streams");
1927 gst_bin_remove (GST_BIN (ebin), muxer);
1934 release_pads (const GValue * item, GstElement * elt)
1936 GstPad *pad = g_value_get_object (item);
1937 GstPad *peer = NULL;
1939 GST_DEBUG_OBJECT (elt, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1941 /* Unlink from its peer pad */
1942 if ((peer = gst_pad_get_peer (pad))) {
1943 if (GST_PAD_DIRECTION (peer) == GST_PAD_SRC)
1944 gst_pad_unlink (peer, pad);
1946 gst_pad_unlink (pad, peer);
1947 gst_object_unref (peer);
1950 /* Release it from the object */
1951 gst_element_release_request_pad (elt, pad);
1955 stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup)
1961 GST_DEBUG_OBJECT (ebin, "Freeing StreamGroup %p", sgroup);
1963 if (sgroup->restriction_sid != 0)
1964 g_signal_handler_disconnect (sgroup->profile, sgroup->restriction_sid);
1967 /* outqueue - Muxer */
1968 tmppad = gst_element_get_static_pad (sgroup->outqueue, "src");
1969 pad = gst_pad_get_peer (tmppad);
1972 /* Remove muxer request sink pad */
1973 gst_pad_unlink (tmppad, pad);
1974 if (GST_PAD_TEMPLATE_PRESENCE (GST_PAD_PAD_TEMPLATE (pad)) ==
1976 gst_element_release_request_pad (ebin->muxer, pad);
1977 gst_object_unref (pad);
1979 gst_object_unref (tmppad);
1981 if (sgroup->outqueue)
1982 gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
1984 if (sgroup->formatter) {
1985 /* capsfilter - formatter - outqueue */
1986 gst_element_set_state (sgroup->formatter, GST_STATE_NULL);
1987 gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
1988 gst_element_unlink (sgroup->formatter, sgroup->outqueue);
1989 gst_element_unlink (sgroup->outfilter, sgroup->formatter);
1991 /* Capsfilter - outqueue */
1992 gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
1993 gst_element_unlink (sgroup->outfilter, sgroup->outqueue);
1995 gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
1996 gst_bin_remove (GST_BIN (ebin), sgroup->outqueue);
1998 /* streamcombiner - parser - capsfilter */
1999 if (sgroup->parser) {
2000 gst_element_set_state (sgroup->parser, GST_STATE_NULL);
2001 gst_element_unlink (sgroup->parser, sgroup->outfilter);
2002 gst_element_unlink (sgroup->combiner, sgroup->parser);
2003 gst_bin_remove ((GstBin *) ebin, sgroup->parser);
2007 if (sgroup->ghostpad) {
2008 if (GST_PAD_PARENT (sgroup->ghostpad) != NULL)
2009 gst_element_remove_pad (GST_ELEMENT_CAST (ebin), sgroup->ghostpad);
2011 gst_object_unref (sgroup->ghostpad);
2014 if (sgroup->inqueue)
2015 gst_element_set_state (sgroup->inqueue, GST_STATE_NULL);
2017 if (sgroup->encoder)
2018 gst_element_set_state (sgroup->encoder, GST_STATE_NULL);
2019 if (sgroup->fakesink)
2020 gst_element_set_state (sgroup->fakesink, GST_STATE_NULL);
2021 if (sgroup->outfilter) {
2022 gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
2024 if (sgroup->outputfilter_caps_sid) {
2025 g_signal_handler_disconnect (sgroup->outfilter->sinkpads->data,
2026 sgroup->outputfilter_caps_sid);
2027 sgroup->outputfilter_caps_sid = 0;
2030 if (sgroup->smartencoder)
2031 gst_element_set_state (sgroup->smartencoder, GST_STATE_NULL);
2033 if (sgroup->capsfilter) {
2034 gst_element_set_state (sgroup->capsfilter, GST_STATE_NULL);
2035 if (sgroup->encoder)
2036 gst_element_unlink (sgroup->capsfilter, sgroup->encoder);
2038 gst_element_unlink (sgroup->capsfilter, sgroup->fakesink);
2039 gst_bin_remove ((GstBin *) ebin, sgroup->capsfilter);
2042 for (tmp = sgroup->converters; tmp; tmp = tmp->next) {
2043 GstElement *elt = (GstElement *) tmp->data;
2045 gst_element_set_state (elt, GST_STATE_NULL);
2046 gst_bin_remove ((GstBin *) ebin, elt);
2048 if (sgroup->converters)
2049 g_list_free (sgroup->converters);
2051 if (sgroup->combiner) {
2052 GstIterator *it = gst_element_iterate_sink_pads (sgroup->combiner);
2053 GstIteratorResult itret = GST_ITERATOR_OK;
2055 while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
2057 gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
2059 gst_iterator_resync (it);
2061 gst_iterator_free (it);
2062 gst_element_set_state (sgroup->combiner, GST_STATE_NULL);
2063 gst_bin_remove ((GstBin *) ebin, sgroup->combiner);
2066 if (sgroup->splitter) {
2067 GstIterator *it = gst_element_iterate_src_pads (sgroup->splitter);
2068 GstIteratorResult itret = GST_ITERATOR_OK;
2069 while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
2071 gst_iterator_foreach (it, (GstIteratorForeachFunction) release_pads,
2073 gst_iterator_resync (it);
2075 gst_iterator_free (it);
2077 gst_element_set_state (sgroup->splitter, GST_STATE_NULL);
2078 gst_bin_remove ((GstBin *) ebin, sgroup->splitter);
2081 if (sgroup->inqueue)
2082 gst_bin_remove ((GstBin *) ebin, sgroup->inqueue);
2084 if (sgroup->encoder)
2085 gst_bin_remove ((GstBin *) ebin, sgroup->encoder);
2087 if (sgroup->fakesink)
2088 gst_bin_remove ((GstBin *) ebin, sgroup->fakesink);
2090 if (sgroup->smartencoder)
2091 gst_bin_remove ((GstBin *) ebin, sgroup->smartencoder);
2093 if (sgroup->outfilter)
2094 gst_bin_remove ((GstBin *) ebin, sgroup->outfilter);
2096 g_slice_free (StreamGroup, sgroup);
2100 stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup)
2102 ebin->streams = g_list_remove (ebin->streams, sgroup);
2104 stream_group_free (ebin, sgroup);
2108 gst_encode_bin_tear_down_profile (GstEncodeBin * ebin)
2110 if (G_UNLIKELY (ebin->profile == NULL))
2113 GST_DEBUG ("Tearing down profile %s",
2114 gst_encoding_profile_get_name (ebin->profile));
2116 while (ebin->streams)
2117 stream_group_remove (ebin, (StreamGroup *) ebin->streams->data);
2119 /* Set ghostpad target to NULL */
2120 gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), NULL);
2122 /* Remove muxer if present */
2124 gst_element_set_state (ebin->muxer, GST_STATE_NULL);
2125 gst_bin_remove (GST_BIN (ebin), ebin->muxer);
2129 /* free/clear profile */
2130 gst_encoding_profile_unref (ebin->profile);
2131 ebin->profile = NULL;
2135 gst_encode_bin_setup_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
2139 g_return_val_if_fail (ebin->profile == NULL, FALSE);
2141 GST_DEBUG ("Setting up profile %p:%s (type:%s)", profile,
2142 gst_encoding_profile_get_name (profile),
2143 gst_encoding_profile_get_type_nick (profile));
2145 ebin->profile = profile;
2146 gst_object_ref (ebin->profile);
2148 /* Create elements */
2149 res = create_elements_and_pads (ebin);
2151 gst_encode_bin_tear_down_profile (ebin);
2157 gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
2159 g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
2161 GST_DEBUG_OBJECT (ebin, "profile (%p) : %s", profile,
2162 gst_encoding_profile_get_name (profile));
2164 if (G_UNLIKELY (ebin->active)) {
2165 GST_WARNING_OBJECT (ebin, "Element already active, can't change profile");
2169 /* If we're not active, we can deactivate the previous profile */
2170 if (ebin->profile) {
2171 gst_encode_bin_tear_down_profile (ebin);
2174 return gst_encode_bin_setup_profile (ebin, profile);
2177 static inline gboolean
2178 gst_encode_bin_activate (GstEncodeBin * ebin)
2180 ebin->active = ebin->profile != NULL;
2181 return ebin->active;
2185 gst_encode_bin_deactivate (GstEncodeBin * ebin)
2189 for (tmp = ebin->streams; tmp; tmp = tmp->next) {
2190 StreamGroup *sgroup = tmp->data;
2191 GstCaps *format = gst_encoding_profile_get_format (sgroup->profile);
2193 _set_group_caps_format (sgroup, sgroup->profile, format);
2196 gst_caps_unref (format);
2199 ebin->active = FALSE;
2202 static GstStateChangeReturn
2203 gst_encode_bin_change_state (GstElement * element, GstStateChange transition)
2205 GstStateChangeReturn ret;
2206 GstEncodeBin *ebin = (GstEncodeBin *) element;
2208 switch (transition) {
2209 case GST_STATE_CHANGE_READY_TO_PAUSED:
2210 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
2211 if (!gst_encode_bin_activate (ebin)) {
2212 ret = GST_STATE_CHANGE_FAILURE;
2221 GST_ELEMENT_CLASS (gst_encode_bin_parent_class)->change_state (element,
2223 if (ret == GST_STATE_CHANGE_FAILURE)
2226 switch (transition) {
2227 case GST_STATE_CHANGE_PAUSED_TO_READY:
2228 gst_encode_bin_deactivate (ebin);
2240 plugin_init (GstPlugin * plugin)
2244 GST_DEBUG_CATEGORY_INIT (gst_encode_bin_debug, "encodebin", 0, "encoder bin");
2247 GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
2249 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
2250 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2251 #endif /* ENABLE_NLS */
2254 res = gst_element_register (plugin, "encodebin", GST_RANK_NONE,
2255 GST_TYPE_ENCODE_BIN);
2260 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2263 "various encoding-related elements", plugin_init, VERSION, GST_LICENSE,
2264 GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)