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