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