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