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