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