tizen 2.0 init
[framework/multimedia/gst-plugins-base0.10.git] / gst / encoding / gstencodebin.c
1 /* GStreamer encoding bin
2  * Copyright (C) 2009 Edward Hervey <edward.hervey@collabora.co.uk>
3  *           (C) 2009 Nokia Corporation
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24
25 #include <string.h>
26 #include "gstencodebin.h"
27 #include "gstsmartencoder.h"
28 #include "gststreamsplitter.h"
29 #include "gststreamcombiner.h"
30 #include <gst/gst-i18n-plugin.h>
31
32 /**
33  * SECTION:element-encodebin
34  *
35  * EncodeBin provides a bin for encoding/muxing various streams according to
36  * a specified #GstEncodingProfile.
37  *
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.
43  *
44  * <refsect2>
45  * <title>Features</title>
46  * <itemizedlist>
47  * <listitem>
48  * Automatic encoder and muxer selection based on elements available on the
49  * system.
50  * </listitem>
51  * <listitem>
52  * Conversion of raw audio/video streams (scaling, framerate conversion,
53  * colorspace conversion, samplerate conversion) to conform to the profile
54  * output format.
55  * </listitem>
56  * <listitem>
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
60  * signal.
61  * </listitem>
62  * <listitem>
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.
66  * </listitem>
67  * <listitem>
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.
72  * </listitem>
73  * <listitem>
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.
78  * </listitem>
79  * <listitem>
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.
84  * </listitem>
85  * <listitem>
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
89  * framerate.
90  * </listitem>
91  * <listitem>
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.
96  * </listitem>
97  * <listitem>
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.
102  * </listitem>
103  * </itemizedlist>
104  * </refsect2>
105  */
106
107
108 /* TODO/FIXME
109  *
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
116  **/
117
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)
120
121 typedef enum
122 {
123   GST_ENC_FLAG_NO_AUDIO_CONVERSION = (1 << 0),
124   GST_ENC_FLAG_NO_VIDEO_CONVERSION = (1 << 1)
125 } GstEncFlags;
126
127 #define GST_TYPE_ENC_FLAGS (gst_enc_flags_get_type())
128 GType gst_enc_flags_get_type (void);
129
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);
134
135 static GstStaticPadTemplate video_sink_template =
136 GST_STATIC_PAD_TEMPLATE ("video_%d",
137     GST_PAD_SINK,
138     GST_PAD_REQUEST,
139     GST_STATIC_CAPS_ANY);
140 static GstStaticPadTemplate audio_sink_template =
141 GST_STATIC_PAD_TEMPLATE ("audio_%d",
142     GST_PAD_SINK,
143     GST_PAD_REQUEST,
144     GST_STATIC_CAPS_ANY);
145 /* static GstStaticPadTemplate text_sink_template = */
146 /* GST_STATIC_PAD_TEMPLATE ("text_%d", */
147 /*     GST_PAD_SINK, */
148 /*     GST_PAD_REQUEST, */
149 /*     GST_STATIC_CAPS_ANY); */
150 static GstStaticPadTemplate private_sink_template =
151 GST_STATIC_PAD_TEMPLATE ("private_%d",
152     GST_PAD_SINK,
153     GST_PAD_REQUEST,
154     GST_STATIC_CAPS_ANY);
155
156 struct _GstEncodeBin
157 {
158   GstBin parent;
159
160   /* the profile field is only valid if it could be entirely setup */
161   GstEncodingProfile *profile;
162
163   GList *streams;               /* List of StreamGroup, not sorted */
164
165   GstElement *muxer;
166   /* Ghostpad with changing target */
167   GstPad *srcpad;
168
169   /* TRUE if in PAUSED/PLAYING */
170   gboolean active;
171
172   /* available muxers, encoders and parsers */
173   GList *muxers;
174   GList *formatters;
175   GList *encoders;
176   GList *parsers;
177
178   /* Increasing counter for unique pad name */
179   guint last_pad_id;
180
181   /* Cached caps for identification */
182   GstCaps *raw_video_caps;
183   GstCaps *raw_audio_caps;
184   /* GstCaps *raw_text_caps; */
185
186   guint queue_buffers_max;
187   guint queue_bytes_max;
188   guint64 queue_time_max;
189
190   guint64 tolerance;
191   gboolean avoid_reencoding;
192
193   GstEncFlags flags;
194 };
195
196 struct _GstEncodeBinClass
197 {
198   GstBinClass parent;
199
200   /* Action Signals */
201   GstPad *(*request_pad) (GstEncodeBin * encodebin, GstCaps * caps);
202 };
203
204 typedef struct _StreamGroup StreamGroup;
205
206 struct _StreamGroup
207 {
208   GstEncodeBin *ebin;
209   GstEncodingProfile *profile;
210   GstPad *ghostpad;             /* Sink ghostpad */
211   GstElement *inqueue;          /* Queue just after the ghostpad */
212   GstElement *splitter;
213   GList *converters;            /* List of conversion GstElement */
214   GstElement *capsfilter;       /* profile->restriction (if non-NULL/ANY) */
215   GstElement *encoder;          /* Encoder (can be NULL) */
216   GstElement *combiner;
217   GstElement *parser;
218   GstElement *smartencoder;
219   GstElement *outfilter;        /* Output capsfilter (streamprofile.format) */
220   GstElement *formatter;
221   GstElement *outqueue;         /* Queue just before the muxer */
222 };
223
224 /* Default for queues (same defaults as queue element) */
225 #define DEFAULT_QUEUE_BUFFERS_MAX  200
226 #define DEFAULT_QUEUE_BYTES_MAX    10 * 1024 * 1024
227 #define DEFAULT_QUEUE_TIME_MAX     GST_SECOND
228 #define DEFAULT_AUDIO_JITTER_TOLERANCE 20 * GST_MSECOND
229 #define DEFAULT_AVOID_REENCODING   FALSE
230 #define DEFAULT_FLAGS              0
231
232 #define DEFAULT_RAW_CAPS                        \
233   "video/x-raw-yuv; "                           \
234   "video/x-raw-rgb; "                           \
235   "video/x-raw-gray; "                          \
236   "audio/x-raw-int; "                           \
237   "audio/x-raw-float; "                         \
238   "text/plain; "                                \
239   "text/x-pango-markup; "                       \
240   "video/x-dvd-subpicture; "                    \
241   "subpicture/x-pgs"
242
243 /* Properties */
244 enum
245 {
246   PROP_0,
247   PROP_PROFILE,
248   PROP_QUEUE_BUFFERS_MAX,
249   PROP_QUEUE_BYTES_MAX,
250   PROP_QUEUE_TIME_MAX,
251   PROP_AUDIO_JITTER_TOLERANCE,
252   PROP_AVOID_REENCODING,
253   PROP_FLAGS,
254   PROP_LAST
255 };
256
257 /* Signals */
258 enum
259 {
260   SIGNAL_REQUEST_PAD,
261   LAST_SIGNAL
262 };
263
264 #define C_FLAGS(v) ((guint) v)
265
266 GType
267 gst_enc_flags_get_type (void)
268 {
269   static const GFlagsValue values[] = {
270     {C_FLAGS (GST_ENC_FLAG_NO_AUDIO_CONVERSION), "Do not use audio conversion "
271           "elements", "no-audio-conversion"},
272     {C_FLAGS (GST_ENC_FLAG_NO_VIDEO_CONVERSION), "Do not use video conversion "
273           "elements", "no-video-conversion"},
274     {0, NULL, NULL}
275   };
276   static volatile GType id = 0;
277
278   if (g_once_init_enter ((gsize *) & id)) {
279     GType _id;
280
281     _id = g_flags_register_static ("GstEncFlags", values);
282
283     g_once_init_leave ((gsize *) & id, _id);
284   }
285
286   return id;
287 }
288
289 static guint gst_encode_bin_signals[LAST_SIGNAL] = { 0 };
290
291 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
292
293 GST_DEBUG_CATEGORY_STATIC (gst_encode_bin_debug);
294 #define GST_CAT_DEFAULT gst_encode_bin_debug
295
296 G_DEFINE_TYPE (GstEncodeBin, gst_encode_bin, GST_TYPE_BIN);
297
298 static void gst_encode_bin_dispose (GObject * object);
299 static void gst_encode_bin_set_property (GObject * object, guint prop_id,
300     const GValue * value, GParamSpec * pspec);
301 static void gst_encode_bin_get_property (GObject * object, guint prop_id,
302     GValue * value, GParamSpec * pspec);
303 static GstStateChangeReturn gst_encode_bin_change_state (GstElement * element,
304     GstStateChange transition);
305
306 static GstPad *gst_encode_bin_request_new_pad (GstElement * element,
307     GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
308 static void gst_encode_bin_release_pad (GstElement * element, GstPad * pad);
309
310 static gboolean
311 gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile);
312 static void gst_encode_bin_tear_down_profile (GstEncodeBin * ebin);
313 static gboolean gst_encode_bin_setup_profile (GstEncodeBin * ebin,
314     GstEncodingProfile * profile);
315
316 static StreamGroup *_create_stream_group (GstEncodeBin * ebin,
317     GstEncodingProfile * sprof, const gchar * sinkpadname, GstCaps * sinkcaps);
318 static void stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup);
319 static GstPad *gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin,
320     GstCaps * caps);
321
322 static inline GstElement *_get_formatter (GstEncodeBin * ebin,
323     GstEncodingProfile * sprof);
324
325 static void
326 gst_encode_bin_class_init (GstEncodeBinClass * klass)
327 {
328   GObjectClass *gobject_klass;
329   GstElementClass *gstelement_klass;
330
331   gobject_klass = (GObjectClass *) klass;
332   gstelement_klass = (GstElementClass *) klass;
333
334   gobject_klass->dispose = gst_encode_bin_dispose;
335   gobject_klass->set_property = gst_encode_bin_set_property;
336   gobject_klass->get_property = gst_encode_bin_get_property;
337
338   /* Properties */
339
340   /**
341    * GstEncodeBin:profile:
342    *
343    * The #GstEncodingProfile to use. This property must be set before going
344    * to %GST_STATE_PAUSED or higher.
345    */
346   g_object_class_install_property (gobject_klass, PROP_PROFILE,
347       gst_param_spec_mini_object ("profile", "Profile",
348           "The GstEncodingProfile to use", GST_TYPE_ENCODING_PROFILE,
349           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
350
351   g_object_class_install_property (gobject_klass, PROP_QUEUE_BYTES_MAX,
352       g_param_spec_uint ("queue-bytes-max", "Max. size (kB)",
353           "Max. amount of data in the queue (bytes, 0=disable)",
354           0, G_MAXUINT, DEFAULT_QUEUE_BYTES_MAX,
355           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
356
357   g_object_class_install_property (gobject_klass, PROP_QUEUE_BUFFERS_MAX,
358       g_param_spec_uint ("queue-buffers-max", "Max. size (buffers)",
359           "Max. number of buffers in the queue (0=disable)", 0, G_MAXUINT,
360           DEFAULT_QUEUE_BUFFERS_MAX,
361           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
362
363   g_object_class_install_property (gobject_klass, PROP_QUEUE_TIME_MAX,
364       g_param_spec_uint64 ("queue-time-max", "Max. size (ns)",
365           "Max. amount of data in the queue (in ns, 0=disable)", 0, G_MAXUINT64,
366           DEFAULT_QUEUE_TIME_MAX, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
367
368   g_object_class_install_property (gobject_klass, PROP_AUDIO_JITTER_TOLERANCE,
369       g_param_spec_uint64 ("audio-jitter-tolerance", "Audio jitter tolerance",
370           "Amount of timestamp jitter/imperfection to allow on audio streams before inserting/dropping samples (ns)",
371           0, G_MAXUINT64, DEFAULT_AUDIO_JITTER_TOLERANCE,
372           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
373
374   g_object_class_install_property (gobject_klass, PROP_AVOID_REENCODING,
375       g_param_spec_boolean ("avoid-reencoding", "Avoid re-encoding",
376           "Whether to re-encode portions of compatible video streams that lay on segment boundaries",
377           DEFAULT_AVOID_REENCODING,
378           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
379
380   /**
381    * GstEncodeBin:flags
382    *
383    * Control the behaviour of encodebin.
384    */
385   g_object_class_install_property (gobject_klass, PROP_FLAGS,
386       g_param_spec_flags ("flags", "Flags", "Flags to control behaviour",
387           GST_TYPE_ENC_FLAGS, DEFAULT_FLAGS,
388           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
389
390   /* Signals */
391   /**
392    * GstEncodeBin::request-pad
393    * @encodebin: a #GstEncodeBin instance
394    * @caps: a #GstCaps
395    *
396    * Use this method to request an unused sink request #GstPad that can take the
397    * provided @caps as input. You must release the pad with
398    * gst_element_release_request_pad() when you are done with it.
399    *
400    * Returns: A compatible #GstPad, or %NULL if no compatible #GstPad could be
401    * created or is available.
402    */
403   gst_encode_bin_signals[SIGNAL_REQUEST_PAD] =
404       g_signal_new ("request-pad", G_TYPE_FROM_CLASS (klass),
405       G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GstEncodeBinClass,
406           request_pad), NULL, NULL, gst_encode_marshal_OBJECT__BOXED,
407       GST_TYPE_PAD, 1, GST_TYPE_CAPS);
408
409   klass->request_pad = gst_encode_bin_request_pad_signal;
410
411   gst_element_class_add_static_pad_template (gstelement_klass,
412       &muxer_src_template);
413   gst_element_class_add_static_pad_template (gstelement_klass,
414       &video_sink_template);
415   gst_element_class_add_static_pad_template (gstelement_klass,
416       &audio_sink_template);
417   /* gst_element_class_add_static_pad_template (gstelement_klass, */
418   /*     &text_sink_template); */
419   gst_element_class_add_static_pad_template (gstelement_klass,
420       &private_sink_template);
421
422   gstelement_klass->change_state =
423       GST_DEBUG_FUNCPTR (gst_encode_bin_change_state);
424   gstelement_klass->request_new_pad_full =
425       GST_DEBUG_FUNCPTR (gst_encode_bin_request_new_pad);
426   gstelement_klass->release_pad =
427       GST_DEBUG_FUNCPTR (gst_encode_bin_release_pad);
428
429   gst_element_class_set_details_simple (gstelement_klass,
430       "Encoder Bin",
431       "Generic/Bin/Encoder",
432       "Convenience encoding/muxing element",
433       "Edward Hervey <edward.hervey@collabora.co.uk>");
434 }
435
436 static void
437 gst_encode_bin_dispose (GObject * object)
438 {
439   GstEncodeBin *ebin = (GstEncodeBin *) object;
440
441   if (ebin->muxers)
442     gst_plugin_feature_list_free (ebin->muxers);
443
444   if (ebin->formatters)
445     gst_plugin_feature_list_free (ebin->formatters);
446
447   if (ebin->encoders)
448     gst_plugin_feature_list_free (ebin->encoders);
449
450   if (ebin->parsers)
451     gst_plugin_feature_list_free (ebin->parsers);
452
453   gst_encode_bin_tear_down_profile (ebin);
454
455   if (ebin->raw_video_caps)
456     gst_caps_unref (ebin->raw_video_caps);
457   if (ebin->raw_audio_caps)
458     gst_caps_unref (ebin->raw_audio_caps);
459   /* if (ebin->raw_text_caps) */
460   /*   gst_caps_unref (ebin->raw_text_caps); */
461
462   G_OBJECT_CLASS (gst_encode_bin_parent_class)->dispose (object);
463 }
464
465 static void
466 gst_encode_bin_init (GstEncodeBin * encode_bin)
467 {
468   GstPadTemplate *tmpl;
469
470   encode_bin->muxers =
471       gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_MUXER,
472       GST_RANK_MARGINAL);
473
474   encode_bin->formatters =
475       gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_FORMATTER,
476       GST_RANK_SECONDARY);
477
478   encode_bin->encoders =
479       gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_ENCODER,
480       GST_RANK_MARGINAL);
481
482   encode_bin->parsers =
483       gst_element_factory_list_get_elements (GST_ELEMENT_FACTORY_TYPE_PARSER,
484       GST_RANK_MARGINAL);
485
486   encode_bin->raw_video_caps =
487       gst_caps_from_string ("video/x-raw-yuv;video/x-raw-rgb;video/x-raw-gray");
488   encode_bin->raw_audio_caps =
489       gst_caps_from_string ("audio/x-raw-int;audio/x-raw-float");
490   /* encode_bin->raw_text_caps = */
491   /*     gst_caps_from_string ("text/plain;text/x-pango-markup"); */
492
493   encode_bin->queue_buffers_max = DEFAULT_QUEUE_BUFFERS_MAX;
494   encode_bin->queue_bytes_max = DEFAULT_QUEUE_BYTES_MAX;
495   encode_bin->queue_time_max = DEFAULT_QUEUE_TIME_MAX;
496   encode_bin->tolerance = DEFAULT_AUDIO_JITTER_TOLERANCE;
497   encode_bin->avoid_reencoding = DEFAULT_AVOID_REENCODING;
498   encode_bin->flags = DEFAULT_FLAGS;
499
500   tmpl = gst_static_pad_template_get (&muxer_src_template);
501   encode_bin->srcpad = gst_ghost_pad_new_no_target_from_template ("src", tmpl);
502   gst_object_unref (tmpl);
503   gst_element_add_pad (GST_ELEMENT_CAST (encode_bin), encode_bin->srcpad);
504 }
505
506 static void
507 gst_encode_bin_set_property (GObject * object, guint prop_id,
508     const GValue * value, GParamSpec * pspec)
509 {
510   GstEncodeBin *ebin = (GstEncodeBin *) object;
511
512   switch (prop_id) {
513     case PROP_PROFILE:
514       gst_encode_bin_set_profile (ebin,
515           (GstEncodingProfile *) gst_value_get_mini_object (value));
516       break;
517     case PROP_QUEUE_BUFFERS_MAX:
518       ebin->queue_buffers_max = g_value_get_uint (value);
519       break;
520     case PROP_QUEUE_BYTES_MAX:
521       ebin->queue_bytes_max = g_value_get_uint (value);
522       break;
523     case PROP_QUEUE_TIME_MAX:
524       ebin->queue_time_max = g_value_get_uint64 (value);
525       break;
526     case PROP_AUDIO_JITTER_TOLERANCE:
527       ebin->tolerance = g_value_get_uint64 (value);
528       break;
529     case PROP_AVOID_REENCODING:
530       ebin->avoid_reencoding = g_value_get_boolean (value);
531       break;
532     case PROP_FLAGS:
533       ebin->flags = g_value_get_flags (value);
534       break;
535     default:
536       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
537       break;
538   }
539 }
540
541 static void
542 gst_encode_bin_get_property (GObject * object, guint prop_id,
543     GValue * value, GParamSpec * pspec)
544 {
545   GstEncodeBin *ebin = (GstEncodeBin *) object;
546
547   switch (prop_id) {
548     case PROP_PROFILE:
549       gst_value_set_mini_object (value, (GstMiniObject *) ebin->profile);
550       break;
551     case PROP_QUEUE_BUFFERS_MAX:
552       g_value_set_uint (value, ebin->queue_buffers_max);
553       break;
554     case PROP_QUEUE_BYTES_MAX:
555       g_value_set_uint (value, ebin->queue_bytes_max);
556       break;
557     case PROP_QUEUE_TIME_MAX:
558       g_value_set_uint64 (value, ebin->queue_time_max);
559       break;
560     case PROP_AUDIO_JITTER_TOLERANCE:
561       g_value_set_uint64 (value, ebin->tolerance);
562       break;
563     case PROP_AVOID_REENCODING:
564       g_value_set_boolean (value, ebin->avoid_reencoding);
565       break;
566     case PROP_FLAGS:
567       g_value_set_flags (value, ebin->flags);
568       break;
569     default:
570       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
571       break;
572   }
573 }
574
575 static inline gboolean
576 are_raw_caps (const GstCaps * caps)
577 {
578   GstCaps *raw = gst_static_caps_get (&default_raw_caps);
579
580   if (gst_caps_can_intersect (caps, raw)) {
581     gst_caps_unref (raw);
582     return TRUE;
583   }
584   gst_caps_unref (raw);
585   return FALSE;
586 }
587
588 /* Returns the number of time a given stream profile is currently used
589  * in encodebin */
590 static inline guint
591 stream_profile_used_count (GstEncodeBin * ebin, GstEncodingProfile * sprof)
592 {
593   guint nbprofused = 0;
594   GList *tmp;
595
596   for (tmp = ebin->streams; tmp; tmp = tmp->next) {
597     StreamGroup *sgroup = (StreamGroup *) tmp->data;
598
599     if (sgroup->profile == sprof)
600       nbprofused++;
601   }
602
603   return nbprofused;
604 }
605
606 static inline GstEncodingProfile *
607 next_unused_stream_profile (GstEncodeBin * ebin, GType ptype, GstCaps * caps)
608 {
609   GST_DEBUG_OBJECT (ebin, "ptype:%s, caps:%" GST_PTR_FORMAT,
610       g_type_name (ptype), caps);
611
612   if (G_UNLIKELY (ptype == G_TYPE_NONE && caps != NULL)) {
613     /* Identify the profile type based on raw caps */
614     if (gst_caps_can_intersect (ebin->raw_video_caps, caps))
615       ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
616     else if (gst_caps_can_intersect (ebin->raw_audio_caps, caps))
617       ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
618     /* else if (gst_caps_can_intersect (ebin->raw_text_caps, caps)) */
619     /*   ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
620     GST_DEBUG_OBJECT (ebin, "Detected profile type as being %s",
621         g_type_name (ptype));
622   }
623
624   if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
625     const GList *tmp;
626
627     for (tmp =
628         gst_encoding_container_profile_get_profiles
629         (GST_ENCODING_CONTAINER_PROFILE (ebin->profile)); tmp;
630         tmp = tmp->next) {
631       GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
632
633       /* Pick an available Stream profile for which:
634        * * either it is of the compatibly raw type,
635        * * OR we can pass it through directly without encoding
636        */
637       if (G_TYPE_FROM_INSTANCE (sprof) == ptype) {
638         guint presence = gst_encoding_profile_get_presence (sprof);
639         GST_DEBUG ("Found a stream profile with the same type");
640         if ((presence == 0)
641             || (presence > stream_profile_used_count (ebin, sprof)))
642           return sprof;
643       } else if ((caps != NULL) && (ptype == G_TYPE_NONE)) {
644         GstCaps *outcaps;
645         gboolean res;
646
647         outcaps = gst_encoding_profile_get_input_caps (sprof);
648         GST_DEBUG ("Unknown stream, seeing if it's compatible with %"
649             GST_PTR_FORMAT, outcaps);
650         res = gst_caps_can_intersect (outcaps, caps);
651         gst_caps_unref (outcaps);
652
653         if (res)
654           return sprof;
655       }
656     }
657   }
658
659   return NULL;
660 }
661
662 static GstPad *
663 request_pad_for_stream (GstEncodeBin * encodebin, GType ptype,
664     const gchar * name, GstCaps * caps)
665 {
666   StreamGroup *sgroup;
667   GstEncodingProfile *sprof;
668
669   GST_DEBUG_OBJECT (encodebin, "name:%s caps:%" GST_PTR_FORMAT, name, caps);
670
671   /* Figure out if we have a unused GstEncodingProfile we can use for
672    * these caps */
673   sprof = next_unused_stream_profile (encodebin, ptype, caps);
674
675   if (G_UNLIKELY (sprof == NULL))
676     goto no_stream_profile;
677
678   sgroup = _create_stream_group (encodebin, sprof, name, caps);
679   if (G_UNLIKELY (sgroup == NULL))
680     goto no_stream_group;
681
682   return sgroup->ghostpad;
683
684 no_stream_profile:
685   {
686     GST_WARNING_OBJECT (encodebin, "Couldn't find a compatible stream profile");
687     return NULL;
688   }
689
690 no_stream_group:
691   {
692     GST_WARNING_OBJECT (encodebin, "Couldn't create a StreamGroup");
693     return NULL;
694   }
695 }
696
697 static GstPad *
698 gst_encode_bin_request_new_pad (GstElement * element,
699     GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
700 {
701   GstEncodeBin *ebin = (GstEncodeBin *) element;
702   GstPad *res = NULL;
703
704   GST_DEBUG_OBJECT (element, "templ:%s, name:%s", templ->name_template, name);
705
706   /* Identify the stream group */
707   if (caps != NULL) {
708     res = request_pad_for_stream (ebin, G_TYPE_NONE, name, (GstCaps *) caps);
709   }
710
711   if (res == NULL) {
712     GType ptype = G_TYPE_NONE;
713
714     if (!strcmp (templ->name_template, "video_%d"))
715       ptype = GST_TYPE_ENCODING_VIDEO_PROFILE;
716     else if (!strcmp (templ->name_template, "audio_%d"))
717       ptype = GST_TYPE_ENCODING_AUDIO_PROFILE;
718     /* else if (!strcmp (templ->name_template, "text_%d")) */
719     /*   ptype = GST_TYPE_ENCODING_TEXT_PROFILE; */
720
721     /* FIXME : Check uniqueness of pad */
722     /* FIXME : Check that the requested number is the last one, and if not,
723      * update the last_pad_id variable so that we don't create a pad with
724      * the same name/number in the future */
725
726     res = request_pad_for_stream (ebin, ptype, name, NULL);
727   }
728
729   return res;
730 }
731
732 static GstPad *
733 gst_encode_bin_request_pad_signal (GstEncodeBin * encodebin, GstCaps * caps)
734 {
735   GstPad *pad = request_pad_for_stream (encodebin, G_TYPE_NONE, NULL, caps);
736
737   return pad ? GST_PAD_CAST (gst_object_ref (pad)) : NULL;
738 }
739
740 static inline StreamGroup *
741 find_stream_group_from_pad (GstEncodeBin * ebin, GstPad * pad)
742 {
743   GList *tmp;
744
745   for (tmp = ebin->streams; tmp; tmp = tmp->next) {
746     StreamGroup *sgroup = (StreamGroup *) tmp->data;
747     if (G_UNLIKELY (sgroup->ghostpad == pad))
748       return sgroup;
749   }
750
751   return NULL;
752 }
753
754 static void
755 gst_encode_bin_release_pad (GstElement * element, GstPad * pad)
756 {
757   GstEncodeBin *ebin = (GstEncodeBin *) element;
758   StreamGroup *sgroup;
759
760   /* Find the associated StreamGroup */
761
762   sgroup = find_stream_group_from_pad (ebin, pad);
763   if (G_UNLIKELY (sgroup == NULL))
764     goto no_stream_group;
765
766   /* Release objects/data associated with the StreamGroup */
767   stream_group_remove (ebin, sgroup);
768
769   return;
770
771 no_stream_group:
772   {
773     GST_WARNING_OBJECT (ebin, "Couldn't find corresponding StreamGroup");
774     return;
775   }
776 }
777
778 /* Create a parser for the given stream profile */
779 static inline GstElement *
780 _get_parser (GstEncodeBin * ebin, GstEncodingProfile * sprof)
781 {
782   GList *parsers1, *parsers, *tmp;
783   GstElement *parser = NULL;
784   GstElementFactory *parserfact = NULL;
785   const GstCaps *format;
786
787   format = gst_encoding_profile_get_format (sprof);
788
789   GST_DEBUG ("Getting list of parsers for format %" GST_PTR_FORMAT, format);
790
791   /* FIXME : requesting twice the parsers twice is a bit ugly, we should
792    * have a method to request on more than one condition */
793   parsers1 =
794       gst_element_factory_list_filter (ebin->parsers, format,
795       GST_PAD_SRC, FALSE);
796   parsers =
797       gst_element_factory_list_filter (parsers1, format, GST_PAD_SINK, FALSE);
798   gst_plugin_feature_list_free (parsers1);
799
800   if (G_UNLIKELY (parsers == NULL)) {
801     GST_DEBUG ("Couldn't find any compatible parsers");
802     return NULL;
803   }
804
805   for (tmp = parsers; tmp; tmp = tmp->next) {
806     /* FIXME : We're only picking the first one so far */
807     /* FIXME : signal the user if he wants this */
808     parserfact = (GstElementFactory *) tmp->data;
809     break;
810   }
811
812   if (parserfact)
813     parser = gst_element_factory_create (parserfact, NULL);
814
815   gst_plugin_feature_list_free (parsers);
816
817   return parser;
818 }
819
820 static GstElement *
821 _create_element_and_set_preset (GstElementFactory * factory,
822     const gchar * preset, const gchar * name)
823 {
824   GstElement *res = NULL;
825
826   GST_DEBUG ("Creating element from factory %s",
827       GST_PLUGIN_FEATURE_NAME (factory));
828   res = gst_element_factory_create (factory, name);
829   if (preset && GST_IS_PRESET (res) &&
830       !gst_preset_load_preset (GST_PRESET (res), preset)) {
831     GST_WARNING ("Couldn't set preset [%s] on element [%s]",
832         preset, GST_PLUGIN_FEATURE_NAME (factory));
833     gst_object_unref (res);
834     res = NULL;
835   }
836
837   return res;
838 }
839
840 /* Create the encoder for the given stream profile */
841 static inline GstElement *
842 _get_encoder (GstEncodeBin * ebin, GstEncodingProfile * sprof)
843 {
844   GList *encoders, *tmp;
845   GstElement *encoder = NULL;
846   GstElementFactory *encoderfact = NULL;
847   const GstCaps *format;
848   const gchar *preset;
849
850   format = gst_encoding_profile_get_format (sprof);
851   preset = gst_encoding_profile_get_preset (sprof);
852
853   GST_DEBUG ("Getting list of encoders for format %" GST_PTR_FORMAT, format);
854
855   /* If stream caps are raw, return identity */
856   if (G_UNLIKELY (are_raw_caps (format))) {
857     GST_DEBUG ("Stream format is raw, returning identity as the encoder");
858     encoder = gst_element_factory_make ("identity", NULL);
859     goto beach;
860   }
861
862   encoders =
863       gst_element_factory_list_filter (ebin->encoders, format,
864       GST_PAD_SRC, FALSE);
865
866   if (G_UNLIKELY (encoders == NULL)) {
867     GST_DEBUG ("Couldn't find any compatible encoders");
868     goto beach;
869   }
870
871   for (tmp = encoders; tmp; tmp = tmp->next) {
872     encoderfact = (GstElementFactory *) tmp->data;
873     if ((encoder = _create_element_and_set_preset (encoderfact, preset, NULL)))
874       break;
875   }
876
877   gst_plugin_feature_list_free (encoders);
878
879 beach:
880   return encoder;
881 }
882
883 static GstPad *
884 local_element_request_pad (GstElement * element, GstPadTemplate * templ,
885     const gchar * name)
886 {
887   GstPad *newpad = NULL;
888   GstElementClass *oclass;
889
890   oclass = GST_ELEMENT_GET_CLASS (element);
891
892   if (oclass->request_new_pad)
893     newpad = (oclass->request_new_pad) (element, templ, name);
894
895   if (newpad)
896     gst_object_ref (newpad);
897
898   return newpad;
899 }
900
901 static GstPad *
902 gst_element_get_pad_from_template (GstElement * element, GstPadTemplate * templ)
903 {
904   GstPad *ret = NULL;
905   GstPadPresence presence;
906
907   /* If this function is ever exported, we need check the validity of `element'
908    * and `templ', and to make sure the template actually belongs to the
909    * element. */
910
911   presence = GST_PAD_TEMPLATE_PRESENCE (templ);
912
913   switch (presence) {
914     case GST_PAD_ALWAYS:
915     case GST_PAD_SOMETIMES:
916       ret = gst_element_get_static_pad (element, templ->name_template);
917       if (!ret && presence == GST_PAD_ALWAYS)
918         g_warning
919             ("Element %s has an ALWAYS template %s, but no pad of the same name",
920             GST_OBJECT_NAME (element), templ->name_template);
921       break;
922
923     case GST_PAD_REQUEST:
924       ret = gst_element_request_pad (element, templ, NULL, NULL);
925       break;
926   }
927
928   return ret;
929 }
930
931 /* FIXME : Improve algorithm for finding compatible muxer sink pad */
932 static inline GstPad *
933 get_compatible_muxer_sink_pad (GstEncodeBin * ebin, GstElement * encoder,
934     const GstCaps * sinkcaps)
935 {
936   GstPad *sinkpad;
937   GstPadTemplate *srctempl = NULL;
938   GstPadTemplate *sinktempl;
939
940   if (encoder) {
941     GstPad *srcpad;
942     srcpad = gst_element_get_static_pad (encoder, "src");
943
944     srctempl = gst_pad_get_pad_template (srcpad);
945
946     GST_DEBUG_OBJECT (ebin,
947         "Attempting to find pad from muxer %s compatible with %s:%s",
948         GST_ELEMENT_NAME (ebin->muxer), GST_DEBUG_PAD_NAME (srcpad));
949
950     gst_object_unref (srcpad);
951     sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
952   } else {
953     srctempl =
954         gst_pad_template_new ("whatever", GST_PAD_SRC, GST_PAD_ALWAYS,
955         gst_caps_copy (sinkcaps));
956     g_assert (srctempl != NULL);
957     sinktempl = gst_element_get_compatible_pad_template (ebin->muxer, srctempl);
958     g_object_unref (srctempl);
959   }
960
961   if (G_UNLIKELY (sinktempl == NULL))
962     goto no_template;
963
964   sinkpad = gst_element_get_pad_from_template (ebin->muxer, sinktempl);
965
966   return sinkpad;
967
968 no_template:
969   {
970     GST_WARNING_OBJECT (ebin, "No compatible pad available on muxer");
971     return NULL;
972   }
973 }
974
975 static gboolean
976 _has_class (GstElement * element, const gchar * classname)
977 {
978   GstElementClass *klass;
979
980   klass = GST_ELEMENT_GET_CLASS (element);
981
982   return strstr (klass->details.klass, classname) != NULL;
983 }
984
985 /* FIXME : Add handling of streams that don't need encoding  */
986 /* FIXME : Add handling of streams that don't require conversion elements */
987 /*
988  * Create the elements, StreamGroup, add the sink pad, link it to the muxer
989  *
990  * sinkpadname: If non-NULL, that name will be assigned to the sink ghost pad
991  * sinkcaps: If non-NULL will be used to figure out how to setup the group */
992 static StreamGroup *
993 _create_stream_group (GstEncodeBin * ebin, GstEncodingProfile * sprof,
994     const gchar * sinkpadname, GstCaps * sinkcaps)
995 {
996   StreamGroup *sgroup = NULL;
997   GstPad *sinkpad, *srcpad, *muxerpad = NULL;
998   /* Element we will link to the encoder */
999   GstElement *last = NULL;
1000   GList *tmp, *tosync = NULL;
1001   const GstCaps *format;
1002   const GstCaps *restriction;
1003   const gchar *missing_element_name;
1004
1005   format = gst_encoding_profile_get_format (sprof);
1006   restriction = gst_encoding_profile_get_restriction (sprof);
1007
1008   GST_DEBUG ("Creating group. format %" GST_PTR_FORMAT ", for caps %"
1009       GST_PTR_FORMAT, format, sinkcaps);
1010   GST_DEBUG ("avoid_reencoding:%d", ebin->avoid_reencoding);
1011
1012   sgroup = g_slice_new0 (StreamGroup);
1013   sgroup->ebin = ebin;
1014   sgroup->profile = sprof;
1015
1016   /* NOTE for people reading this code:
1017    * 
1018    * We construct the group starting by the furthest downstream element
1019    * and making our way up adding/syncing/linking as we go.
1020    *
1021    * There are two parallel paths:
1022    * * One for raw data which goes through converters and encoders
1023    * * One for already encoded data
1024    */
1025
1026   /* Exception to the rule above:
1027    * We check if we have an available encoder so we can abort early */
1028   /* FIXME : What if we only want to do passthrough ??? */
1029   GST_LOG ("Checking for encoder availability");
1030   sgroup->encoder = _get_encoder (ebin, sprof);
1031   if (G_UNLIKELY (sgroup->encoder == NULL))
1032     goto no_encoder;
1033
1034   /* Muxer.
1035    * If we are handling a container profile, figure out if the muxer has a
1036    * sinkpad compatible with the selected profile */
1037   if (ebin->muxer) {
1038     muxerpad = get_compatible_muxer_sink_pad (ebin, NULL, format);
1039     if (G_UNLIKELY (muxerpad == NULL))
1040       goto no_muxer_pad;
1041
1042   }
1043
1044   /* Output Queue.
1045    * We only use a 1buffer long queue here, the actual queueing will be done
1046    * in the input queue */
1047   last = sgroup->outqueue = gst_element_factory_make ("queue", NULL);
1048   g_object_set (sgroup->outqueue, "max-size-buffers", (guint32) 1,
1049       "max-size-bytes", (guint32) 0, "max-size-time", (guint64) 0,
1050       "silent", TRUE, NULL);
1051
1052   gst_bin_add (GST_BIN (ebin), sgroup->outqueue);
1053   tosync = g_list_append (tosync, sgroup->outqueue);
1054   srcpad = gst_element_get_static_pad (sgroup->outqueue, "src");
1055   if (muxerpad) {
1056     if (G_UNLIKELY (fast_pad_link (srcpad, muxerpad) != GST_PAD_LINK_OK)) {
1057       goto muxer_link_failure;
1058     }
1059     gst_object_unref (muxerpad);
1060   } else {
1061     gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), srcpad);
1062   }
1063   gst_object_unref (srcpad);
1064
1065   /* Check if we need a formatter
1066    * If we have no muxer or
1067    * if the muxer isn't a formatter and doesn't implement the tagsetter interface
1068    */
1069   if (!ebin->muxer
1070       || (!gst_element_implements_interface (ebin->muxer, GST_TYPE_TAG_SETTER)
1071           && !_has_class (ebin->muxer, "Formatter"))) {
1072     sgroup->formatter = _get_formatter (ebin, sprof);
1073     if (sgroup->formatter) {
1074       GST_DEBUG ("Adding formatter for %" GST_PTR_FORMAT, format);
1075
1076       gst_bin_add (GST_BIN (ebin), sgroup->formatter);
1077       tosync = g_list_append (tosync, sgroup->formatter);
1078       if (G_UNLIKELY (!fast_element_link (sgroup->formatter, last)))
1079         goto formatter_link_failure;
1080       last = sgroup->formatter;
1081     }
1082   }
1083
1084
1085   /* Output capsfilter
1086    * This will receive the format caps from the streamprofile */
1087   GST_DEBUG ("Adding output capsfilter for %" GST_PTR_FORMAT, format);
1088   sgroup->outfilter = gst_element_factory_make ("capsfilter", NULL);
1089   g_object_set (sgroup->outfilter, "caps", format, NULL);
1090
1091   gst_bin_add (GST_BIN (ebin), sgroup->outfilter);
1092   tosync = g_list_append (tosync, sgroup->outfilter);
1093   if (G_UNLIKELY (!fast_element_link (sgroup->outfilter, last)))
1094     goto outfilter_link_failure;
1095   last = sgroup->outfilter;
1096
1097
1098   sgroup->parser = _get_parser (ebin, sprof);
1099
1100   if (sgroup->parser != NULL) {
1101     GST_DEBUG ("Got a parser %s", GST_ELEMENT_NAME (sgroup->parser));
1102     gst_bin_add (GST_BIN (ebin), sgroup->parser);
1103     tosync = g_list_append (tosync, sgroup->parser);
1104     if (G_UNLIKELY (!gst_element_link (sgroup->parser, last)))
1105       goto parser_link_failure;
1106     last = sgroup->parser;
1107   }
1108
1109   /* Stream combiner */
1110   sgroup->combiner = g_object_new (GST_TYPE_STREAM_COMBINER, NULL);
1111
1112   gst_bin_add (GST_BIN (ebin), sgroup->combiner);
1113   tosync = g_list_append (tosync, sgroup->combiner);
1114   if (G_UNLIKELY (!fast_element_link (sgroup->combiner, last)))
1115     goto combiner_link_failure;
1116
1117
1118   /* Stream splitter */
1119   sgroup->splitter = g_object_new (GST_TYPE_STREAM_SPLITTER, NULL);
1120
1121   gst_bin_add (GST_BIN (ebin), sgroup->splitter);
1122   tosync = g_list_append (tosync, sgroup->splitter);
1123
1124   /* Input queue
1125    * FIXME : figure out what max-size to use for the input queue */
1126   sgroup->inqueue = gst_element_factory_make ("queue", NULL);
1127   g_object_set (sgroup->inqueue, "max-size-buffers",
1128       (guint32) ebin->queue_buffers_max, "max-size-bytes",
1129       (guint32) ebin->queue_bytes_max, "max-size-time",
1130       (guint64) ebin->queue_time_max, "silent", TRUE, NULL);
1131
1132   gst_bin_add (GST_BIN (ebin), sgroup->inqueue);
1133   tosync = g_list_append (tosync, sgroup->inqueue);
1134   if (G_UNLIKELY (!fast_element_link (sgroup->inqueue, sgroup->splitter)))
1135     goto splitter_link_failure;
1136
1137   /* Expose input queue sink pad as ghostpad */
1138   sinkpad = gst_element_get_static_pad (sgroup->inqueue, "sink");
1139   if (sinkpadname == NULL) {
1140     gchar *pname =
1141         g_strdup_printf ("%s_%d", gst_encoding_profile_get_type_nick (sprof),
1142         ebin->last_pad_id++);
1143     GST_DEBUG ("Adding ghost pad %s", pname);
1144     sgroup->ghostpad = gst_ghost_pad_new (pname, sinkpad);
1145     g_free (pname);
1146   } else
1147     sgroup->ghostpad = gst_ghost_pad_new (sinkpadname, sinkpad);
1148   gst_object_unref (sinkpad);
1149
1150
1151   /* Path 1 : Already-encoded data */
1152   sinkpad =
1153       local_element_request_pad (sgroup->combiner, NULL, "passthroughsink");
1154   if (G_UNLIKELY (sinkpad == NULL))
1155     goto no_combiner_sinkpad;
1156
1157   if (ebin->avoid_reencoding) {
1158     GstCaps *tmpcaps;
1159
1160     GST_DEBUG ("Asked to use Smart Encoder");
1161     sgroup->smartencoder = g_object_new (GST_TYPE_SMART_ENCODER, NULL);
1162
1163     /* Check if stream format is compatible */
1164     srcpad = gst_element_get_static_pad (sgroup->smartencoder, "src");
1165     tmpcaps = gst_pad_get_caps_reffed (srcpad);
1166     if (!gst_caps_can_intersect (tmpcaps, format)) {
1167       GST_DEBUG ("We don't have a smart encoder for the stream format");
1168       gst_object_unref (sgroup->smartencoder);
1169       sgroup->smartencoder = NULL;
1170     } else {
1171       gst_bin_add ((GstBin *) ebin, sgroup->smartencoder);
1172       fast_pad_link (srcpad, sinkpad);
1173       tosync = g_list_append (tosync, sgroup->smartencoder);
1174       sinkpad = gst_element_get_static_pad (sgroup->smartencoder, "sink");
1175     }
1176     gst_caps_unref (tmpcaps);
1177     g_object_unref (srcpad);
1178   }
1179
1180   srcpad = local_element_request_pad (sgroup->splitter, NULL, "passthroughsrc");
1181   if (G_UNLIKELY (srcpad == NULL))
1182     goto no_splitter_srcpad;
1183
1184   /* Go straight to splitter */
1185   if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1186     goto passthrough_link_failure;
1187   g_object_unref (sinkpad);
1188   g_object_unref (srcpad);
1189
1190
1191   /* Path 2 : Conversion / Encoding */
1192
1193   /* 1. Create the encoder */
1194   GST_LOG ("Adding encoder");
1195   last = sgroup->encoder;
1196   gst_bin_add ((GstBin *) ebin, sgroup->encoder);
1197   tosync = g_list_append (tosync, sgroup->encoder);
1198
1199   sinkpad = local_element_request_pad (sgroup->combiner, NULL, "encodingsink");
1200   if (G_UNLIKELY (sinkpad == NULL))
1201     goto no_combiner_sinkpad;
1202   srcpad = gst_element_get_static_pad (sgroup->encoder, "src");
1203   if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1204     goto encoder_link_failure;
1205   g_object_unref (sinkpad);
1206   g_object_unref (srcpad);
1207
1208
1209   /* 3. Create the conversion/restriction elements */
1210   /* 3.1. capsfilter */
1211   if (restriction && !gst_caps_is_any (restriction)) {
1212     GST_LOG ("Adding capsfilter for restriction caps : %" GST_PTR_FORMAT,
1213         restriction);
1214
1215     last = sgroup->capsfilter = gst_element_factory_make ("capsfilter", NULL);
1216     g_object_set (sgroup->capsfilter, "caps", restriction, NULL);
1217     gst_bin_add ((GstBin *) ebin, sgroup->capsfilter);
1218     tosync = g_list_append (tosync, sgroup->capsfilter);
1219     fast_element_link (sgroup->capsfilter, sgroup->encoder);
1220   }
1221
1222   /* 3.2. restriction elements */
1223   /* FIXME : Once we have properties for specific converters, use those */
1224   if (GST_IS_ENCODING_VIDEO_PROFILE (sprof)) {
1225     const gboolean native_video =
1226         ! !(ebin->flags & GST_ENC_FLAG_NO_VIDEO_CONVERSION);
1227     GstElement *cspace = NULL, *scale, *vrate, *cspace2 = NULL;
1228
1229     GST_LOG ("Adding conversion elements for video stream");
1230
1231     if (!native_video) {
1232       cspace = gst_element_factory_make ("ffmpegcolorspace", NULL);
1233       scale = gst_element_factory_make ("videoscale", NULL);
1234       if (!scale) {
1235         missing_element_name = "videoscale";
1236         goto missing_element;
1237       }
1238       /* 4-tap scaling and black borders */
1239       g_object_set (scale, "method", 2, "add-borders", TRUE, NULL);
1240       cspace2 = gst_element_factory_make ("ffmpegcolorspace", NULL);
1241
1242       if (!cspace || !cspace2) {
1243         missing_element_name = "ffmpegcolorspace";
1244         goto missing_element;
1245       }
1246
1247       gst_bin_add_many ((GstBin *) ebin, cspace, scale, cspace2, NULL);
1248       tosync = g_list_append (tosync, cspace);
1249       tosync = g_list_append (tosync, scale);
1250       tosync = g_list_append (tosync, cspace2);
1251
1252       sgroup->converters = g_list_prepend (sgroup->converters, cspace);
1253       sgroup->converters = g_list_prepend (sgroup->converters, scale);
1254       sgroup->converters = g_list_prepend (sgroup->converters, cspace2);
1255
1256       if (!fast_element_link (cspace, scale) ||
1257           !fast_element_link (scale, cspace2))
1258         goto converter_link_failure;
1259     }
1260
1261     if (!gst_encoding_video_profile_get_variableframerate
1262         (GST_ENCODING_VIDEO_PROFILE (sprof))) {
1263       vrate = gst_element_factory_make ("videorate", NULL);
1264       if (!vrate) {
1265         missing_element_name = "videorate";
1266         goto missing_element;
1267       }
1268
1269       gst_bin_add ((GstBin *) ebin, vrate);
1270       tosync = g_list_prepend (tosync, vrate);
1271       sgroup->converters = g_list_prepend (sgroup->converters, vrate);
1272
1273       if ((!native_video && !fast_element_link (cspace2, vrate))
1274           || !fast_element_link (vrate, last))
1275         goto converter_link_failure;
1276
1277       if (!native_video)
1278         last = cspace;
1279       else
1280         last = vrate;
1281     } else if (!native_video) {
1282       if (!fast_element_link (cspace2, last))
1283         goto converter_link_failure;
1284       last = cspace;
1285     }
1286
1287   } else if (GST_IS_ENCODING_AUDIO_PROFILE (sprof)
1288       && !(ebin->flags & GST_ENC_FLAG_NO_AUDIO_CONVERSION)) {
1289     GstElement *aconv, *ares, *arate, *aconv2;
1290
1291     GST_LOG ("Adding conversion elements for audio stream");
1292
1293     arate = gst_element_factory_make ("audiorate", NULL);
1294     g_object_set (arate, "tolerance", (guint64) ebin->tolerance, NULL);
1295     if (!arate) {
1296       missing_element_name = "audiorate";
1297       goto missing_element;
1298     }
1299     aconv = gst_element_factory_make ("audioconvert", NULL);
1300     aconv2 = gst_element_factory_make ("audioconvert", NULL);
1301     ares = gst_element_factory_make ("audioresample", NULL);
1302     if (!aconv || !aconv2) {
1303       missing_element_name = "audioconvert";
1304       goto missing_element;
1305     }
1306     if (!ares) {
1307       missing_element_name = "audioresample";
1308       goto missing_element;
1309     }
1310
1311     gst_bin_add_many ((GstBin *) ebin, arate, aconv, ares, aconv2, NULL);
1312     tosync = g_list_append (tosync, arate);
1313     tosync = g_list_append (tosync, aconv);
1314     tosync = g_list_append (tosync, ares);
1315     tosync = g_list_append (tosync, aconv2);
1316     if (!fast_element_link (arate, aconv) ||
1317         !fast_element_link (aconv, ares) ||
1318         !fast_element_link (ares, aconv2) || !fast_element_link (aconv2, last))
1319       goto converter_link_failure;
1320
1321     sgroup->converters = g_list_prepend (sgroup->converters, arate);
1322     sgroup->converters = g_list_prepend (sgroup->converters, aconv);
1323     sgroup->converters = g_list_prepend (sgroup->converters, ares);
1324     sgroup->converters = g_list_prepend (sgroup->converters, aconv2);
1325
1326     last = arate;
1327   }
1328
1329   /* Link to stream splitter */
1330   sinkpad = gst_element_get_static_pad (last, "sink");
1331   srcpad = local_element_request_pad (sgroup->splitter, NULL, "encodingsrc");
1332   if (G_UNLIKELY (srcpad == NULL))
1333     goto no_splitter_srcpad;
1334   if (G_UNLIKELY (fast_pad_link (srcpad, sinkpad) != GST_PAD_LINK_OK))
1335     goto splitter_encoding_failure;
1336   g_object_unref (sinkpad);
1337   g_object_unref (srcpad);
1338
1339   /* End of Stream 2 setup */
1340
1341   /* Sync all elements to parent state */
1342   for (tmp = tosync; tmp; tmp = tmp->next)
1343     gst_element_sync_state_with_parent ((GstElement *) tmp->data);
1344   g_list_free (tosync);
1345
1346   /* Add ghostpad */
1347   GST_DEBUG ("Adding ghostpad %s:%s", GST_DEBUG_PAD_NAME (sgroup->ghostpad));
1348   gst_pad_set_active (sgroup->ghostpad, TRUE);
1349   gst_element_add_pad ((GstElement *) ebin, sgroup->ghostpad);
1350
1351   /* Add StreamGroup to our list of streams */
1352
1353   GST_DEBUG
1354       ("Done creating elements, adding StreamGroup to our controlled stream list");
1355
1356   ebin->streams = g_list_prepend (ebin->streams, sgroup);
1357
1358   return sgroup;
1359
1360 splitter_encoding_failure:
1361   GST_ERROR_OBJECT (ebin, "Error linking splitter to encoding stream");
1362   goto cleanup;
1363
1364 no_encoder:
1365   GST_ERROR_OBJECT (ebin, "Couldn't create encoder for format %" GST_PTR_FORMAT,
1366       format);
1367   /* missing plugin support */
1368   gst_element_post_message (GST_ELEMENT_CAST (ebin),
1369       gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin), format));
1370   GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL),
1371       ("Couldn't create encoder for format %" GST_PTR_FORMAT, format));
1372   goto cleanup;
1373
1374 no_muxer_pad:
1375   GST_ERROR_OBJECT (ebin,
1376       "Couldn't find a compatible muxer pad to link encoder to");
1377   goto cleanup;
1378
1379 missing_element:
1380   gst_element_post_message (GST_ELEMENT_CAST (ebin),
1381       gst_missing_element_message_new (GST_ELEMENT_CAST (ebin),
1382           missing_element_name));
1383   GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN,
1384       (_("Missing element '%s' - check your GStreamer installation."),
1385           missing_element_name), (NULL));
1386   goto cleanup;
1387
1388 encoder_link_failure:
1389   GST_ERROR_OBJECT (ebin, "Failed to link the encoder");
1390   goto cleanup;
1391
1392 muxer_link_failure:
1393   GST_ERROR_OBJECT (ebin, "Couldn't link encoder to muxer");
1394   goto cleanup;
1395
1396 formatter_link_failure:
1397   GST_ERROR_OBJECT (ebin, "Couldn't link output filter to output queue");
1398   goto cleanup;
1399
1400 outfilter_link_failure:
1401   GST_ERROR_OBJECT (ebin,
1402       "Couldn't link output filter to output queue/formatter");
1403   goto cleanup;
1404
1405 passthrough_link_failure:
1406   GST_ERROR_OBJECT (ebin, "Failed linking splitter in passthrough mode");
1407   goto cleanup;
1408
1409 no_splitter_srcpad:
1410   GST_ERROR_OBJECT (ebin, "Couldn't get a source pad from the splitter");
1411   goto cleanup;
1412
1413 no_combiner_sinkpad:
1414   GST_ERROR_OBJECT (ebin, "Couldn't get a sink pad from the combiner");
1415   goto cleanup;
1416
1417 splitter_link_failure:
1418   GST_ERROR_OBJECT (ebin, "Failure linking to the splitter");
1419   goto cleanup;
1420
1421 combiner_link_failure:
1422   GST_ERROR_OBJECT (ebin, "Failure linking to the combiner");
1423   goto cleanup;
1424
1425 parser_link_failure:
1426   GST_ERROR_OBJECT (ebin, "Failure linking the parser");
1427   goto cleanup;
1428
1429 converter_link_failure:
1430   GST_ERROR_OBJECT (ebin, "Failure linking the video converters");
1431   goto cleanup;
1432
1433 cleanup:
1434   /* FIXME : Actually properly cleanup everything */
1435   g_slice_free (StreamGroup, sgroup);
1436   return NULL;
1437 }
1438
1439 static gboolean
1440 _gst_caps_match_foreach (GQuark field_id, const GValue * value, gpointer data)
1441 {
1442   GstStructure *structure = data;
1443   const GValue *other_value = gst_structure_id_get_value (structure, field_id);
1444
1445   if (G_UNLIKELY (other_value == NULL))
1446     return FALSE;
1447   if (gst_value_compare (value, other_value) == GST_VALUE_EQUAL) {
1448     return TRUE;
1449   }
1450
1451   return FALSE;
1452 }
1453
1454 /*
1455  * checks that there is at least one structure on caps_a that has
1456  * all its fields exactly the same as one structure on caps_b
1457  */
1458 static gboolean
1459 _gst_caps_match (const GstCaps * caps_a, const GstCaps * caps_b)
1460 {
1461   gint i, j;
1462   gboolean res = FALSE;
1463
1464   for (i = 0; i < gst_caps_get_size (caps_a); i++) {
1465     GstStructure *structure_a = gst_caps_get_structure (caps_a, i);
1466     for (j = 0; j < gst_caps_get_size (caps_b); j++) {
1467       GstStructure *structure_b = gst_caps_get_structure (caps_b, j);
1468
1469       res = gst_structure_foreach (structure_a, _gst_caps_match_foreach,
1470           structure_b);
1471       if (res)
1472         goto end;
1473     }
1474   }
1475 end:
1476   return res;
1477 }
1478
1479 static gboolean
1480 _factory_can_handle_caps (GstElementFactory * factory, const GstCaps * caps,
1481     GstPadDirection dir, gboolean exact)
1482 {
1483   GList *templates = factory->staticpadtemplates;
1484
1485   while (templates) {
1486     GstStaticPadTemplate *template = (GstStaticPadTemplate *) templates->data;
1487
1488     if (template->direction == dir) {
1489       GstCaps *tmp = gst_static_caps_get (&template->static_caps);
1490
1491       if ((exact && _gst_caps_match (caps, tmp)) ||
1492           (!exact && gst_caps_can_intersect (tmp, caps))) {
1493         gst_caps_unref (tmp);
1494         return TRUE;
1495       }
1496       gst_caps_unref (tmp);
1497     }
1498     templates = g_list_next (templates);
1499   }
1500
1501   return FALSE;
1502 }
1503
1504 static inline GstElement *
1505 _get_formatter (GstEncodeBin * ebin, GstEncodingProfile * sprof)
1506 {
1507   GList *formatters, *tmpfmtr;
1508   GstElement *formatter = NULL;
1509   GstElementFactory *formatterfact = NULL;
1510   const GstCaps *format;
1511   const gchar *preset;
1512
1513   format = gst_encoding_profile_get_format (sprof);
1514   preset = gst_encoding_profile_get_preset (sprof);
1515
1516   GST_DEBUG ("Getting list of formatters for format %" GST_PTR_FORMAT, format);
1517
1518   formatters =
1519       gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
1520       FALSE);
1521
1522   if (formatters == NULL)
1523     goto beach;
1524
1525   /* FIXME : signal the user if he wants this */
1526   for (tmpfmtr = formatters; tmpfmtr; tmpfmtr = tmpfmtr->next) {
1527     formatterfact = (GstElementFactory *) tmpfmtr->data;
1528
1529     GST_DEBUG_OBJECT (ebin, "Trying formatter %s",
1530         GST_PLUGIN_FEATURE_NAME (formatterfact));
1531
1532     if ((formatter =
1533             _create_element_and_set_preset (formatterfact, preset, NULL)))
1534       break;
1535   }
1536
1537   gst_plugin_feature_list_free (formatters);
1538
1539 beach:
1540   return formatter;
1541 }
1542
1543 static gint
1544 compare_elements (gconstpointer a, gconstpointer b, gpointer udata)
1545 {
1546   GstCaps *caps = udata;
1547   GstElementFactory *fac_a = (GstElementFactory *) a;
1548   GstElementFactory *fac_b = (GstElementFactory *) b;
1549
1550   /* FIXME not quite sure this is the best algorithm to order the elements
1551    * Some caps similarity comparison algorithm would fit better than going
1552    * boolean (equals/not equals).
1553    */
1554   gboolean equals_a = _factory_can_handle_caps (fac_a, caps, GST_PAD_SRC, TRUE);
1555   gboolean equals_b = _factory_can_handle_caps (fac_b, caps, GST_PAD_SRC, TRUE);
1556
1557   if (equals_a == equals_b) {
1558     return gst_plugin_feature_get_rank ((GstPluginFeature *) fac_b) -
1559         gst_plugin_feature_get_rank ((GstPluginFeature *) fac_a);
1560   } else if (equals_a) {
1561     return -1;
1562   } else if (equals_b) {
1563     return 1;
1564   }
1565   return 0;
1566 }
1567
1568 static inline GstElement *
1569 _get_muxer (GstEncodeBin * ebin)
1570 {
1571   GList *muxers, *formatters, *tmpmux;
1572   GstElement *muxer = NULL;
1573   GstElementFactory *muxerfact = NULL;
1574   const GList *tmp;
1575   const GstCaps *format;
1576   const gchar *preset;
1577
1578   format = gst_encoding_profile_get_format (ebin->profile);
1579   preset = gst_encoding_profile_get_preset (ebin->profile);
1580
1581   GST_DEBUG ("Getting list of muxers for format %" GST_PTR_FORMAT, format);
1582
1583   muxers =
1584       gst_element_factory_list_filter (ebin->muxers, format, GST_PAD_SRC, TRUE);
1585
1586   formatters =
1587       gst_element_factory_list_filter (ebin->formatters, format, GST_PAD_SRC,
1588       TRUE);
1589
1590   muxers = g_list_sort_with_data (muxers, compare_elements, (gpointer) format);
1591   formatters =
1592       g_list_sort_with_data (formatters, compare_elements, (gpointer) format);
1593
1594   muxers = g_list_concat (muxers, formatters);
1595
1596   if (muxers == NULL)
1597     goto beach;
1598
1599   /* FIXME : signal the user if he wants this */
1600   for (tmpmux = muxers; tmpmux; tmpmux = tmpmux->next) {
1601     gboolean cansinkstreams = TRUE;
1602     const GList *profiles =
1603         gst_encoding_container_profile_get_profiles
1604         (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
1605
1606     muxerfact = (GstElementFactory *) tmpmux->data;
1607
1608     GST_DEBUG ("Trying muxer %s", GST_PLUGIN_FEATURE_NAME (muxerfact));
1609
1610     /* See if the muxer can sink all of our stream profile caps */
1611     for (tmp = profiles; tmp; tmp = tmp->next) {
1612       GstEncodingProfile *sprof = (GstEncodingProfile *) tmp->data;
1613
1614       if (!_factory_can_handle_caps (muxerfact,
1615               gst_encoding_profile_get_format (sprof), GST_PAD_SINK, FALSE)) {
1616         GST_DEBUG ("Skipping muxer because it can't sink caps %"
1617             GST_PTR_FORMAT, gst_encoding_profile_get_format (sprof));
1618         cansinkstreams = FALSE;
1619         break;
1620       }
1621     }
1622
1623     /* Only use a muxer than can use all streams and than can accept the
1624      * preset (which may be present or not) */
1625     if (cansinkstreams && (muxer =
1626             _create_element_and_set_preset (muxerfact, preset, "muxer")))
1627       break;
1628   }
1629
1630   gst_plugin_feature_list_free (muxers);
1631
1632 beach:
1633   return muxer;
1634 }
1635
1636 static gboolean
1637 create_elements_and_pads (GstEncodeBin * ebin)
1638 {
1639   gboolean ret = TRUE;
1640   GstElement *muxer = NULL;
1641   GstPad *muxerpad;
1642   const GList *tmp, *profiles;
1643   GstEncodingProfile *sprof;
1644
1645   GST_DEBUG ("Current profile : %s",
1646       gst_encoding_profile_get_name (ebin->profile));
1647
1648   if (GST_IS_ENCODING_CONTAINER_PROFILE (ebin->profile)) {
1649     /* 1. Get the compatible muxer */
1650     muxer = _get_muxer (ebin);
1651     if (G_UNLIKELY (muxer == NULL))
1652       goto no_muxer;
1653
1654     /* Record the muxer */
1655     ebin->muxer = muxer;
1656     gst_bin_add ((GstBin *) ebin, muxer);
1657
1658     /* 2. Ghost the muxer source pad */
1659
1660     /* FIXME : We should figure out if it's a static/request/dyamic pad, 
1661      * but for the time being let's assume it's a static pad :) */
1662     muxerpad = gst_element_get_static_pad (muxer, "src");
1663     if (G_UNLIKELY (muxerpad == NULL))
1664       goto no_muxer_pad;
1665
1666     if (!gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), muxerpad))
1667       goto no_muxer_ghost_pad;
1668
1669     gst_object_unref (muxerpad);
1670     /* 3. Activate fixed presence streams */
1671     profiles =
1672         gst_encoding_container_profile_get_profiles
1673         (GST_ENCODING_CONTAINER_PROFILE (ebin->profile));
1674     for (tmp = profiles; tmp; tmp = tmp->next) {
1675       sprof = (GstEncodingProfile *) tmp->data;
1676
1677       GST_DEBUG ("Trying stream profile with presence %d",
1678           gst_encoding_profile_get_presence (sprof));
1679
1680       if (gst_encoding_profile_get_presence (sprof) != 0) {
1681         if (G_UNLIKELY (_create_stream_group (ebin, sprof, NULL, NULL) == NULL))
1682           goto stream_error;
1683       }
1684     }
1685   } else {
1686     if (G_UNLIKELY (_create_stream_group (ebin, ebin->profile, NULL,
1687                 NULL) == NULL))
1688       goto stream_error;
1689   }
1690
1691   return ret;
1692
1693 no_muxer:
1694   {
1695     GST_WARNING ("No available muxer for %" GST_PTR_FORMAT,
1696         gst_encoding_profile_get_format (ebin->profile));
1697     /* missing plugin support */
1698     gst_element_post_message (GST_ELEMENT_CAST (ebin),
1699         gst_missing_encoder_message_new (GST_ELEMENT_CAST (ebin),
1700             gst_encoding_profile_get_format (ebin->profile)));
1701     GST_ELEMENT_ERROR (ebin, CORE, MISSING_PLUGIN, (NULL),
1702         ("No available muxer for format %" GST_PTR_FORMAT,
1703             gst_encoding_profile_get_format (ebin->profile)));
1704     return FALSE;
1705   }
1706
1707 no_muxer_pad:
1708   {
1709     GST_WARNING ("Can't get source pad from muxer (%s)",
1710         GST_ELEMENT_NAME (muxer));
1711     gst_bin_remove (GST_BIN (ebin), muxer);
1712     return FALSE;
1713   }
1714
1715 no_muxer_ghost_pad:
1716   {
1717     GST_WARNING ("Couldn't set %s:%s as source ghostpad target",
1718         GST_DEBUG_PAD_NAME (muxerpad));
1719     gst_bin_remove (GST_BIN (ebin), muxer);
1720     gst_object_unref (muxerpad);
1721     return FALSE;
1722   }
1723
1724 stream_error:
1725   {
1726     GST_WARNING ("Could not create Streams");
1727     if (muxer)
1728       gst_bin_remove (GST_BIN (ebin), muxer);
1729     ebin->muxer = NULL;
1730     return FALSE;
1731   }
1732 }
1733
1734 static void
1735 release_pads (GstPad * pad, GstElement * elt)
1736 {
1737   GstPad *peer = NULL;
1738
1739   GST_DEBUG_OBJECT (elt, "Releasing pad %s:%s", GST_DEBUG_PAD_NAME (pad));
1740
1741   /* Unlink from its peer pad */
1742   if ((peer = gst_pad_get_peer (pad))) {
1743     if (GST_PAD_DIRECTION (peer) == GST_PAD_SRC)
1744       gst_pad_unlink (peer, pad);
1745     else
1746       gst_pad_unlink (pad, peer);
1747     gst_object_unref (peer);
1748   }
1749
1750   /* Release it from the object */
1751   gst_element_release_request_pad (elt, pad);
1752
1753   /* And remove the reference added by the iterator */
1754   gst_object_unref (pad);
1755 }
1756
1757 static void inline
1758 stream_group_free (GstEncodeBin * ebin, StreamGroup * sgroup)
1759 {
1760   GList *tmp;
1761   GstPad *tmppad;
1762   GstPad *pad;
1763
1764   GST_DEBUG_OBJECT (ebin, "Freeing StreamGroup %p", sgroup);
1765
1766   if (ebin->muxer) {
1767     /* outqueue - Muxer */
1768     tmppad = gst_element_get_static_pad (sgroup->outqueue, "src");
1769     pad = gst_pad_get_peer (tmppad);
1770
1771     /* Remove muxer request sink pad */
1772     gst_pad_unlink (tmppad, pad);
1773     gst_element_release_request_pad (ebin->muxer, pad);
1774     gst_object_unref (tmppad);
1775     gst_object_unref (pad);
1776   }
1777   if (sgroup->outqueue)
1778     gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
1779
1780   if (sgroup->formatter) {
1781     /* capsfilter - formatter - outqueue */
1782     gst_element_set_state (sgroup->formatter, GST_STATE_NULL);
1783     gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
1784     gst_element_unlink (sgroup->formatter, sgroup->outqueue);
1785     gst_element_unlink (sgroup->outfilter, sgroup->formatter);
1786   } else {
1787     /* Capsfilter - outqueue */
1788     gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
1789     gst_element_unlink (sgroup->outfilter, sgroup->outqueue);
1790   }
1791   gst_element_set_state (sgroup->outqueue, GST_STATE_NULL);
1792   gst_bin_remove (GST_BIN (ebin), sgroup->outqueue);
1793
1794   /* streamcombiner - parser - capsfilter */
1795   if (sgroup->parser) {
1796     gst_element_set_state (sgroup->parser, GST_STATE_NULL);
1797     gst_element_unlink (sgroup->parser, sgroup->outfilter);
1798     gst_element_unlink (sgroup->combiner, sgroup->parser);
1799     gst_bin_remove ((GstBin *) ebin, sgroup->parser);
1800   }
1801
1802   /* Sink Ghostpad */
1803   if (sgroup->ghostpad)
1804     gst_element_remove_pad (GST_ELEMENT_CAST (ebin), sgroup->ghostpad);
1805
1806   if (sgroup->inqueue)
1807     gst_element_set_state (sgroup->inqueue, GST_STATE_NULL);
1808
1809   if (sgroup->encoder)
1810     gst_element_set_state (sgroup->encoder, GST_STATE_NULL);
1811   if (sgroup->outfilter)
1812     gst_element_set_state (sgroup->outfilter, GST_STATE_NULL);
1813   if (sgroup->smartencoder)
1814     gst_element_set_state (sgroup->smartencoder, GST_STATE_NULL);
1815
1816   if (sgroup->capsfilter) {
1817     gst_element_set_state (sgroup->capsfilter, GST_STATE_NULL);
1818     gst_element_unlink (sgroup->capsfilter, sgroup->encoder);
1819     gst_bin_remove ((GstBin *) ebin, sgroup->capsfilter);
1820   }
1821
1822   for (tmp = sgroup->converters; tmp; tmp = tmp->next) {
1823     GstElement *elt = (GstElement *) tmp->data;
1824
1825     gst_element_set_state (elt, GST_STATE_NULL);
1826     gst_bin_remove ((GstBin *) ebin, elt);
1827   }
1828   if (sgroup->converters)
1829     g_list_free (sgroup->converters);
1830
1831   if (sgroup->combiner) {
1832     GstIterator *it = gst_element_iterate_sink_pads (sgroup->combiner);
1833     GstIteratorResult itret = GST_ITERATOR_OK;
1834
1835     while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
1836       itret = gst_iterator_foreach (it, (GFunc) release_pads, sgroup->combiner);
1837       gst_iterator_resync (it);
1838     }
1839     gst_iterator_free (it);
1840     gst_element_set_state (sgroup->combiner, GST_STATE_NULL);
1841     gst_bin_remove ((GstBin *) ebin, sgroup->combiner);
1842   }
1843
1844   if (sgroup->splitter) {
1845     GstIterator *it = gst_element_iterate_src_pads (sgroup->splitter);
1846     GstIteratorResult itret = GST_ITERATOR_OK;
1847     while (itret == GST_ITERATOR_OK || itret == GST_ITERATOR_RESYNC) {
1848       itret = gst_iterator_foreach (it, (GFunc) release_pads, sgroup->splitter);
1849       gst_iterator_resync (it);
1850     }
1851     gst_iterator_free (it);
1852
1853     gst_element_set_state (sgroup->splitter, GST_STATE_NULL);
1854     gst_bin_remove ((GstBin *) ebin, sgroup->splitter);
1855   }
1856
1857   if (sgroup->inqueue)
1858     gst_bin_remove ((GstBin *) ebin, sgroup->inqueue);
1859
1860   if (sgroup->encoder)
1861     gst_bin_remove ((GstBin *) ebin, sgroup->encoder);
1862
1863   if (sgroup->smartencoder)
1864     gst_bin_remove ((GstBin *) ebin, sgroup->smartencoder);
1865
1866   if (sgroup->outfilter)
1867     gst_bin_remove ((GstBin *) ebin, sgroup->outfilter);
1868
1869   g_slice_free (StreamGroup, sgroup);
1870 }
1871
1872 static void
1873 stream_group_remove (GstEncodeBin * ebin, StreamGroup * sgroup)
1874 {
1875   ebin->streams = g_list_remove (ebin->streams, sgroup);
1876
1877   stream_group_free (ebin, sgroup);
1878 }
1879
1880 static void
1881 gst_encode_bin_tear_down_profile (GstEncodeBin * ebin)
1882 {
1883   if (G_UNLIKELY (ebin->profile == NULL))
1884     return;
1885
1886   GST_DEBUG ("Tearing down profile %s",
1887       gst_encoding_profile_get_name (ebin->profile));
1888
1889   while (ebin->streams)
1890     stream_group_remove (ebin, (StreamGroup *) ebin->streams->data);
1891
1892   /* Set ghostpad target to NULL */
1893   gst_ghost_pad_set_target (GST_GHOST_PAD (ebin->srcpad), NULL);
1894
1895   /* Remove muxer if present */
1896   if (ebin->muxer) {
1897     gst_element_set_state (ebin->muxer, GST_STATE_NULL);
1898     gst_bin_remove (GST_BIN (ebin), ebin->muxer);
1899     ebin->muxer = NULL;
1900   }
1901
1902   /* free/clear profile */
1903   gst_encoding_profile_unref (ebin->profile);
1904   ebin->profile = NULL;
1905 }
1906
1907 static gboolean
1908 gst_encode_bin_setup_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
1909 {
1910   gboolean res;
1911
1912   g_return_val_if_fail (ebin->profile == NULL, FALSE);
1913
1914   GST_DEBUG ("Setting up profile %s (type:%s)",
1915       gst_encoding_profile_get_name (profile),
1916       gst_encoding_profile_get_type_nick (profile));
1917
1918   ebin->profile = profile;
1919   gst_mini_object_ref ((GstMiniObject *) ebin->profile);
1920
1921   /* Create elements */
1922   res = create_elements_and_pads (ebin);
1923   if (res == FALSE)
1924     gst_encode_bin_tear_down_profile (ebin);
1925
1926   return res;
1927 }
1928
1929 static gboolean
1930 gst_encode_bin_set_profile (GstEncodeBin * ebin, GstEncodingProfile * profile)
1931 {
1932   g_return_val_if_fail (GST_IS_ENCODING_PROFILE (profile), FALSE);
1933
1934   GST_DEBUG_OBJECT (ebin, "profile : %s",
1935       gst_encoding_profile_get_name (profile));
1936
1937   if (G_UNLIKELY (ebin->active)) {
1938     GST_WARNING_OBJECT (ebin, "Element already active, can't change profile");
1939     return FALSE;
1940   }
1941
1942   /* If we're not active, we can deactivate the previous profile */
1943   if (ebin->profile) {
1944     gst_encode_bin_tear_down_profile (ebin);
1945   }
1946
1947   return gst_encode_bin_setup_profile (ebin, profile);
1948 }
1949
1950 static inline gboolean
1951 gst_encode_bin_activate (GstEncodeBin * ebin)
1952 {
1953   ebin->active = ebin->profile != NULL;
1954   return ebin->active;
1955 }
1956
1957 static void
1958 gst_encode_bin_deactivate (GstEncodeBin * ebin)
1959 {
1960   ebin->active = FALSE;
1961 }
1962
1963 static GstStateChangeReturn
1964 gst_encode_bin_change_state (GstElement * element, GstStateChange transition)
1965 {
1966   GstStateChangeReturn ret;
1967   GstEncodeBin *ebin = (GstEncodeBin *) element;
1968
1969   switch (transition) {
1970     case GST_STATE_CHANGE_READY_TO_PAUSED:
1971     case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
1972       if (!gst_encode_bin_activate (ebin)) {
1973         ret = GST_STATE_CHANGE_FAILURE;
1974         goto beach;
1975       }
1976       break;
1977     default:
1978       break;
1979   }
1980
1981   ret =
1982       GST_ELEMENT_CLASS (gst_encode_bin_parent_class)->change_state (element,
1983       transition);
1984   if (ret == GST_STATE_CHANGE_FAILURE)
1985     goto beach;
1986
1987   switch (transition) {
1988     case GST_STATE_CHANGE_PAUSED_TO_READY:
1989       gst_encode_bin_deactivate (ebin);
1990       break;
1991     default:
1992       break;
1993   }
1994
1995 beach:
1996   return ret;
1997 }
1998
1999
2000 static gboolean
2001 plugin_init (GstPlugin * plugin)
2002 {
2003   gboolean res;
2004
2005   GST_DEBUG_CATEGORY_INIT (gst_encode_bin_debug, "encodebin", 0, "encoder bin");
2006
2007 #ifdef ENABLE_NLS
2008   GST_DEBUG ("binding text domain %s to locale dir %s", GETTEXT_PACKAGE,
2009       LOCALEDIR);
2010   bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
2011   bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
2012 #endif /* ENABLE_NLS */
2013
2014
2015   res = gst_element_register (plugin, "encodebin", GST_RANK_NONE,
2016       GST_TYPE_ENCODE_BIN);
2017
2018   return res;
2019 }
2020
2021 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
2022     GST_VERSION_MINOR,
2023     "encoding",
2024     "various encoding-related elements", plugin_init, VERSION, GST_LICENSE,
2025     GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN)