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