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