2 * Copyright (c) 2015 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
18 #include "media_streamer_gst.h"
19 #include "media_streamer_gst_webrtc.h"
20 #include "media_streamer_node.h"
22 #define MS_PADS_UNLINK(pad, peer) GST_PAD_IS_SRC(pad) ? \
23 gst_pad_unlink(pad, peer) : \
24 gst_pad_unlink(peer, pad)
25 #define H264_PARSER_CONFIG_INTERVAL 5
26 #define H264_ENCODER_ZEROLATENCY 0x00000004
28 #define MEDIASTREAMER_DECODEBIN_TYPE_DECODER "video_decoder"
31 MEDIA_STREAMER_SINK_BIN_NORMAL,
32 MEDIA_STREAMER_SINK_BIN_RTP_SERVER,
33 MEDIA_STREAMER_SINK_BIN_ADAPTIVE,
34 } media_streamer_sink_bin_type_e;
36 static int __ms_adaptive_sink_prepare(media_streamer_s *ms_streamer);
38 void ms_generate_dots(GstElement *bin, gchar *name_tag)
41 ms_retm_if(bin == NULL, "bin is NULL");
44 dot_name = g_strdup(DOT_FILE_NAME);
46 dot_name = g_strconcat(DOT_FILE_NAME, ".", name_tag, NULL);
48 GST_DEBUG_BIN_TO_DOT_FILE_WITH_TS(GST_BIN(bin), GST_DEBUG_GRAPH_SHOW_ALL, dot_name);
50 MS_SAFE_GFREE(dot_name);
53 int ms_add_no_target_ghostpad(GstElement *gst_bin, const char *ghost_pad_name, GstPadDirection pad_direction)
55 int ret = MEDIA_STREAMER_ERROR_NONE;
56 gchar *bin_name = NULL;
57 GstPad *ghost_pad = NULL;
61 ms_retvm_if(gst_bin == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "gst_bin is NULL");
63 bin_name = gst_element_get_name(gst_bin);
64 ghost_pad = gst_ghost_pad_new_no_target(ghost_pad_name, pad_direction);
65 if (gst_element_add_pad(GST_ELEMENT(gst_bin), ghost_pad)) {
66 gst_pad_set_active(ghost_pad, TRUE);
67 ms_info("Added [%s] empty ghostpad into [%s]", ghost_pad_name, bin_name);
69 ms_info("Error: Failed to add empty [%s] ghostpad into [%s]", ghost_pad_name, bin_name);
70 ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
73 MS_SAFE_GFREE(bin_name);
80 static gboolean __ms_add_ghostpad(GstElement *gst_element, const char *pad_name, GstElement *gst_bin, const char *ghost_pad_name)
83 GstPad *ghost_pad = NULL;
84 GstPad *element_pad = NULL;
88 ms_retvm_if(!gst_element, FALSE, "gst_element is NULL");
89 ms_retvm_if(!pad_name, FALSE, "pad_name is NULL");
90 ms_retvm_if(!gst_bin, FALSE, "gst_bin is NULL");
92 element_pad = gst_element_get_static_pad(gst_element, pad_name);
94 /* Check, if pad is not static, get it by request */
95 if (element_pad == NULL)
96 element_pad = gst_element_get_request_pad(gst_element, pad_name);
98 ghost_pad = gst_ghost_pad_new(ghost_pad_name, element_pad);
99 ms_retvm_if(!ghost_pad, FALSE, "ghost_pad is NULL");
101 gst_pad_set_active(ghost_pad, TRUE);
103 ret = gst_element_add_pad(GST_ELEMENT(gst_bin), ghost_pad);
106 ms_info("Added %s ghostpad from [%s] into [%s]", pad_name, GST_ELEMENT_NAME(gst_element), GST_ELEMENT_NAME(gst_bin));
108 ms_error("Error: element [%s] does not have valid [%s] pad for adding into [%s] bin", GST_ELEMENT_NAME(gst_element), pad_name, GST_ELEMENT_NAME(gst_bin));
110 MS_SAFE_UNREF(element_pad);
117 /* This unlinks from its peer and ghostpads on its way */
118 static gboolean __ms_pad_peer_unlink(GstPad *pad)
121 GstPad *peer_pad = NULL;
125 ms_retvm_if(!pad, FALSE, "pad is NULL");
127 if (!gst_pad_is_linked(pad))
130 peer_pad = gst_pad_get_peer(pad);
131 ms_retvm_if(!peer_pad, FALSE, "Fail to get peer pad");
133 if (GST_IS_PROXY_PAD(peer_pad)) {
135 GstObject *ghost_object = gst_pad_get_parent(peer_pad);
136 if (GST_IS_GHOST_PAD(ghost_object)) {
137 GstPad *ghost_pad = GST_PAD(ghost_object);
138 GstPad *target_pad = gst_pad_get_peer(ghost_pad);
140 if (target_pad && GST_IS_GHOST_PAD(target_pad))
141 ret = ret && gst_element_remove_pad(GST_ELEMENT(GST_PAD_PARENT(target_pad)), target_pad);
143 /* This is a usual static pad */
145 ret = ret && MS_PADS_UNLINK(ghost_pad, target_pad);
147 ms_info("Ghost Pad [%s] does not have target.", GST_PAD_NAME(ghost_pad));
149 ret = ret && gst_element_remove_pad(GST_ELEMENT(GST_PAD_PARENT(ghost_pad)), ghost_pad);
151 MS_SAFE_UNREF(target_pad);
152 MS_SAFE_UNREF(ghost_pad);
154 MS_SAFE_UNREF(ghost_object);
156 } else if (GST_IS_GHOST_PAD(peer_pad)) {
157 ret = ret && gst_element_remove_pad(GST_ELEMENT(GST_PAD_PARENT(peer_pad)), peer_pad);
159 /* This is a usual static pad */
160 ret = ret && MS_PADS_UNLINK(pad, peer_pad);
163 MS_SAFE_UNREF(peer_pad);
170 static GstElement *__ms_pad_get_peer_element(GstPad *pad)
172 GstPad *peer_pad = NULL;
173 GstElement *ret = NULL;
177 ms_retvm_if(!pad, NULL, "pad is NULL");
179 if (!gst_pad_is_linked(pad)) {
180 ms_info("Pad [%s:%s] is not linked yet", GST_DEBUG_PAD_NAME(pad));
184 peer_pad = gst_pad_get_peer(pad);
185 ms_retvm_if(!peer_pad, NULL, "Fail to get peer pad");
187 ret = gst_pad_get_parent_element(peer_pad);
189 if (GST_IS_PROXY_PAD(peer_pad)) {
190 GstPad *ghost_pad = GST_PAD(gst_pad_get_parent(peer_pad));
191 GstPad *target_pad = gst_pad_get_peer(ghost_pad);
192 if (GST_GHOST_PAD(target_pad)) {
193 GstPad *element_pad = gst_ghost_pad_get_target(GST_GHOST_PAD(target_pad));
194 ret = gst_pad_get_parent_element(element_pad);
195 MS_SAFE_UNREF(element_pad);
197 /* This is a usual static pad */
198 ret = gst_pad_get_parent_element(target_pad);
201 MS_SAFE_UNREF(target_pad);
202 MS_SAFE_UNREF(ghost_pad);
203 } else if (GST_IS_GHOST_PAD(peer_pad)) {
204 GstPad *element_pad = gst_ghost_pad_get_target(GST_GHOST_PAD(peer_pad));
205 ret = gst_pad_get_parent_element(element_pad);
206 MS_SAFE_UNREF(element_pad);
208 /* This is a usual static pad */
209 ret = gst_pad_get_parent_element(peer_pad);
212 MS_SAFE_UNREF(peer_pad);
219 gboolean ms_element_unlink(GstElement *element)
223 GValue elem = G_VALUE_INIT;
224 GstIterator *pad_iterator = NULL;
228 ms_retvm_if(!element, FALSE, "element is NULL");
230 pad_iterator = gst_element_iterate_pads(element);
231 while (GST_ITERATOR_OK == gst_iterator_next(pad_iterator, &elem)) {
232 pad = (GstPad *) g_value_get_object(&elem);
233 ret = ret && __ms_pad_peer_unlink(pad);
234 g_value_reset(&elem);
236 g_value_unset(&elem);
237 gst_iterator_free(pad_iterator);
244 gboolean ms_bin_remove_element(GstElement *element)
246 GstElement *parent = NULL;
247 gboolean ret = FALSE;
251 ms_retvm_if(!element, FALSE, "element is NULL");
253 parent = (GstElement *) gst_element_get_parent(element);
255 /* Remove node's element from bin that decreases ref count */
256 if (parent != NULL) {
257 ret = gst_bin_remove(GST_BIN(parent), element);
259 ms_debug("Element [%s] removed from [%s] bin", GST_ELEMENT_NAME(element), GST_ELEMENT_NAME(parent));
262 MS_SAFE_UNREF(parent);
269 gboolean ms_bin_add_element(GstElement *bin, GstElement *element, gboolean do_ref)
271 GstElement *parent = NULL;
272 gboolean ret = FALSE;
276 ms_retvm_if(!bin, FALSE, "bin is NULL");
277 ms_retvm_if(!element, FALSE, "element is NULL");
279 parent = (GstElement *) gst_element_get_parent(element);
281 /* Add node's element into bin and increases ref count if needed */
282 if (parent == NULL) {
283 ret = gst_bin_add(GST_BIN(bin), element);
285 ms_debug("Element [%s] added into [%s] bin", GST_ELEMENT_NAME(element), GST_ELEMENT_NAME(bin));
286 gst_object_ref(element);
287 gst_element_sync_state_with_parent(element);
290 ms_error("Element [%s] is already added into the [%s] bin", GST_ELEMENT_NAME(element), GST_ELEMENT_NAME(parent));
291 g_object_unref(parent);
299 const gchar *ms_get_pad_type(GstPad *element_pad)
301 const gchar *pad_type = NULL;
302 GstCaps *pad_caps = NULL;
306 ms_retvm_if(!element_pad, NULL, "element_pad is NULL");
308 pad_caps = gst_pad_query_caps(element_pad, 0);
309 MS_GET_CAPS_TYPE(pad_caps, pad_type);
310 gst_caps_unref(pad_caps);
317 static GstElement *__ms_find_peer_element_by_type(GstElement *previous_element, GstPad *prev_elem_src_pad, node_info_s *node_klass_type)
319 GstElement *peer_element = NULL;
320 GstIterator *src_pad_iterator = NULL;
321 GValue src_pad_value = G_VALUE_INIT;
322 const gchar *found_klass = NULL;
326 ms_retvm_if(!previous_element, NULL, "previous_element is NULL");
327 ms_retvm_if(!node_klass_type, NULL, "node_klass_type is NULL");
328 ms_retvm_if(!node_klass_type->klass_name, NULL, "node_klass_type->klass_name is NULL");
329 ms_retvm_if(!node_klass_type->default_name, NULL, "node_klass_type->default_name is NULL");
331 if (prev_elem_src_pad) {
333 /* Check if previous element`s source pad is connected with element */
334 peer_element = __ms_pad_get_peer_element(prev_elem_src_pad);
336 found_klass = gst_element_factory_get_klass(gst_element_get_factory(peer_element));
337 if (g_strrstr(found_klass, node_klass_type->klass_name) || g_strrstr(GST_ELEMENT_NAME(peer_element), node_klass_type->default_name))
338 ms_info(" Found peer element [%s] ", GST_ELEMENT_NAME(peer_element));
340 MS_SAFE_UNREF(peer_element);
344 /* Check if any of previous element`s source pads is connected with element */
345 src_pad_iterator = gst_element_iterate_src_pads(previous_element);
346 while (GST_ITERATOR_OK == gst_iterator_next(src_pad_iterator, &src_pad_value)) {
347 GstPad *src_pad = (GstPad *) g_value_get_object(&src_pad_value);
348 peer_element = __ms_pad_get_peer_element(src_pad);
350 found_klass = gst_element_factory_get_klass(gst_element_get_factory(peer_element));
351 if (g_strrstr(found_klass, node_klass_type->klass_name) || g_strrstr(GST_ELEMENT_NAME(peer_element), node_klass_type->default_name)) {
352 ms_info(" Found peer element [%s] ", GST_ELEMENT_NAME(peer_element));
353 g_value_reset(&src_pad_value);
356 MS_SAFE_UNREF(peer_element);
358 g_value_reset(&src_pad_value);
360 g_value_unset(&src_pad_value);
361 gst_iterator_free(src_pad_iterator);
365 ms_info(" Element [%s] is not connected", GST_ELEMENT_NAME(previous_element));
372 static gboolean __ms_link_two_elements(GstElement *previous_element, GstPad *prev_elem_src_pad, GstElement *found_element)
374 GValue src_pad_value = G_VALUE_INIT;
375 gboolean elements_linked = FALSE;
376 GstPad * found_sink_pad = NULL;
377 GstElement *peer_element = NULL;
378 GstIterator *src_pad_iterator = NULL;
379 GstPad *src_pad = NULL;
383 ms_retvm_if(!previous_element, FALSE, "previous_element is NULL");
384 ms_retvm_if(!found_element, FALSE, "found_element is NULL");
386 if (prev_elem_src_pad) {
387 peer_element = __ms_pad_get_peer_element(prev_elem_src_pad);
388 if (!gst_pad_is_linked(prev_elem_src_pad)) {
390 /* Check compatibility of previous element and unlinked found element */
391 found_sink_pad = gst_element_get_compatible_pad(found_element, prev_elem_src_pad, NULL);
393 elements_linked = gst_element_link_pads(previous_element, GST_PAD_NAME(prev_elem_src_pad), found_element, GST_PAD_NAME(found_sink_pad));
394 } else if (peer_element == found_element) {
395 elements_linked = TRUE;
397 MS_SAFE_UNREF(peer_element);
400 /* Check if previous element has any unlinked src pad */
401 src_pad_iterator = gst_element_iterate_src_pads(previous_element);
402 while (GST_ITERATOR_OK == gst_iterator_next(src_pad_iterator, &src_pad_value)) {
403 src_pad = (GstPad *) g_value_get_object(&src_pad_value);
404 GstElement *peer_element = __ms_pad_get_peer_element(src_pad);
405 if (!gst_pad_is_linked(src_pad)) {
407 /* Check compatibility of previous element and unlinked found element */
408 found_sink_pad = gst_element_get_compatible_pad(found_element, src_pad, NULL);
409 if (found_sink_pad) {
410 elements_linked = gst_element_link_pads(previous_element, GST_PAD_NAME(src_pad), found_element, GST_PAD_NAME(found_sink_pad));
411 if (elements_linked) {
412 g_value_reset(&src_pad_value);
413 MS_SAFE_UNREF(peer_element);
417 } else if (peer_element == found_element) {
418 elements_linked = TRUE;
420 MS_SAFE_UNREF(peer_element);
421 g_value_reset(&src_pad_value);
423 g_value_unset(&src_pad_value);
424 gst_iterator_free(src_pad_iterator);
427 if (found_sink_pad) {
429 ms_info("Succeeded to link [%s] -> [%s]", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(found_element));
431 ms_debug("Failed to link [%s] and [%s]", GST_ELEMENT_NAME(previous_element), GST_ELEMENT_NAME(found_element));
433 ms_info("Element [%s] has no free compatible pad to be connected with [%s] or linked", GST_ELEMENT_NAME(found_element), GST_ELEMENT_NAME(previous_element));
435 MS_SAFE_UNREF(found_sink_pad);
439 return elements_linked;
442 static GstElement *__ms_bin_find_element_and_link_by_type(GstElement *previous_element, GstPad *prev_elem_src_pad, GstElement *search_bin, node_info_s *node_klass_type)
444 GValue element_value = G_VALUE_INIT;
445 GstElement *found_element = NULL;
446 gboolean elements_linked = FALSE;
447 const gchar *found_klass = NULL;
448 GstIterator *bin_iterator = NULL;
452 ms_retvm_if(!previous_element, NULL, "previous_element is NULL");
453 ms_retvm_if(!search_bin, NULL, "search_bin is NULL");
454 ms_retvm_if(!node_klass_type, NULL, "node_klass_type is NULL");
455 ms_retvm_if(!node_klass_type->default_name, NULL, "node_klass_type->default_name is NULL");
457 bin_iterator = gst_bin_iterate_sorted(GST_BIN(search_bin));
459 while (GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &element_value)) {
460 found_element = (GstElement *) g_value_get_object(&element_value);
461 found_klass = gst_element_factory_get_klass(gst_element_get_factory(found_element));
463 /* Check if found element is of appropriate needed plugin class */
464 if (g_strrstr(found_klass, node_klass_type->klass_name) ||
465 g_strrstr(GST_ELEMENT_NAME(found_element), node_klass_type->default_name)) {
466 ms_info("Found element by type [%s]", GST_ELEMENT_NAME(found_element));
467 if (__ms_link_two_elements(previous_element, prev_elem_src_pad, found_element)) {
468 elements_linked = TRUE;
469 g_value_reset(&element_value);
470 g_object_ref(found_element);
474 g_value_reset(&element_value);
477 g_value_unset(&element_value);
478 gst_iterator_free(bin_iterator);
482 return elements_linked ? found_element : NULL;
485 GstElement *ms_find_element_in_bin_by_type(GstElement *bin, node_info_s *node_klass_type)
487 GValue element_value = G_VALUE_INIT;
488 GstElement *found_element = NULL;
489 GstElement *next_element = NULL;
490 const gchar *found_klass = NULL;
491 GstIterator *bin_iterator = NULL;
495 ms_retvm_if(!bin, NULL, "bin is NULL");
496 ms_retvm_if(!node_klass_type, NULL, "node_klass_type is NULL");
497 ms_retvm_if(!node_klass_type->default_name, NULL, "node_klass_type->default_name is NULL");
499 bin_iterator = gst_bin_iterate_sorted(GST_BIN(bin));
501 while (GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &element_value)) {
502 next_element = (GstElement *) g_value_get_object(&element_value);
503 found_klass = gst_element_factory_get_klass(gst_element_get_factory(next_element));
505 if (g_strrstr(found_klass, node_klass_type->klass_name) ||
506 g_strrstr(GST_ELEMENT_NAME(next_element), node_klass_type->default_name)) {
507 ms_info("Found element by type [%s]", GST_ELEMENT_NAME(next_element));
508 found_element = next_element;
512 g_value_reset(&element_value);
515 gst_iterator_free(bin_iterator);
519 return found_element;
522 GstElement *ms_find_element_in_bin_by_name(GstElement *bin, const gchar *name)
524 GValue element_value = G_VALUE_INIT;
525 GstElement *found_element = NULL;
526 GstElement *next_element = NULL;
527 GstIterator *bin_iterator = NULL;
531 ms_retvm_if(!bin, NULL, "bin is NULL");
532 ms_retvm_if(!name, NULL, "name is NULL");
534 bin_iterator = gst_bin_iterate_sorted(GST_BIN(bin));
536 while (GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &element_value)) {
537 next_element = (GstElement *) g_value_get_object(&element_value);
539 if (g_strrstr(GST_ELEMENT_NAME(next_element), name)) {
540 ms_info("Found element by name [%s]", GST_ELEMENT_NAME(next_element));
541 found_element = next_element;
545 g_value_reset(&element_value);
548 gst_iterator_free(bin_iterator);
552 return found_element;
555 static int __ms_factory_rank_compare(GstPluginFeature *first_feature, GstPluginFeature *second_feature)
558 guint first_rank = 0, second_rank = 0;
560 first_rank = gst_plugin_feature_get_rank(first_feature);
561 second_rank = gst_plugin_feature_get_rank(second_feature);
562 ms_debug("second[%s]_rank(%d) - first[%s]_rank(%d) = (%d)",
563 GST_OBJECT_NAME(GST_ELEMENT_FACTORY(second_feature)), second_rank,
564 GST_OBJECT_NAME(GST_ELEMENT_FACTORY(first_feature)), first_rank, second_rank - first_rank);
567 return second_rank - first_rank;
570 GstElement *ms_combine_next_element(GstElement *previous_element, GstPad *prev_elem_src_pad, GstElement *bin_to_find_in, media_streamer_node_type_e node_type)
572 GstCaps *prev_caps = NULL;
573 GstElement *found_element = NULL;
574 node_info_s *node_klass_type = NULL;
576 ms_retvm_if(!previous_element, NULL, "previous_element is NULL");
577 ms_retvm_if(!bin_to_find_in, NULL, "bin_to_find_in is NULL");
581 node_klass_type = ms_node_get_klass_by_its_type(node_type);
583 /* - 1 - If previous element is linked - check for peer element */
584 found_element = __ms_find_peer_element_by_type(GST_ELEMENT(previous_element), prev_elem_src_pad, node_klass_type);
586 /* - 2 - If previous element is not linked - find in bin by type */
588 found_element = __ms_bin_find_element_and_link_by_type(previous_element, prev_elem_src_pad, bin_to_find_in, node_klass_type);
590 /* - 3 - If element by type is not found in bin - create element by type */
591 if (!found_element) {
593 /* Create Node type information for a New element */
594 if (prev_elem_src_pad)
595 prev_caps = gst_pad_query_caps(prev_elem_src_pad, 0);
597 GstPad *src_pad = gst_element_get_static_pad(previous_element, "src");
599 prev_caps = gst_pad_query_caps(src_pad, 0);
600 MS_SAFE_UNREF(src_pad);
602 node_plug_s plug_info = {node_klass_type, NULL, prev_caps, NULL};
604 /* Create Node by ini or registry */
605 found_element = ms_node_element_create(&plug_info, node_type);
607 ms_info("New Element [%s] is created ", GST_ELEMENT_NAME(found_element));
609 /* Add created element */
610 if (ms_bin_add_element(bin_to_find_in, found_element, TRUE)) {
611 gst_element_sync_state_with_parent(found_element);
612 __ms_link_two_elements(previous_element, prev_elem_src_pad, found_element);
613 ms_generate_dots(bin_to_find_in, GST_ELEMENT_NAME(found_element));
615 ms_error("Element [%s] was not added into [%s] bin", GST_ELEMENT_NAME(found_element), GST_ELEMENT_NAME(bin_to_find_in));
616 MS_SAFE_UNREF(found_element);
619 ms_info("New Element is not created ");
621 ms_info("Next element is not combined");
623 MS_SAFE_UNREF(previous_element);
627 return found_element;
630 static gint __decodebin_autoplug_select_cb(GstElement *bin, GstPad *pad, GstCaps *caps, GstElementFactory *factory, gpointer data)
632 /* NOTE : GstAutoplugSelectResult is defined in gstplay-enum.h but not exposed */
634 GST_AUTOPLUG_SELECT_TRY,
635 GST_AUTOPLUG_SELECT_EXPOSE,
636 GST_AUTOPLUG_SELECT_SKIP
637 } GstAutoplugSelectResult;
640 gchar *factory_name = NULL;
641 const gchar *klass = NULL;
642 GstAutoplugSelectResult result = GST_AUTOPLUG_SELECT_TRY;
643 media_streamer_s *ms_streamer = (media_streamer_s *) data;
647 ms_retvm_if(!factory, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "factory is NULL");
648 ms_retvm_if(!ms_streamer, GST_AUTOPLUG_SELECT_TRY, "data is NULL");
650 factory_name = GST_OBJECT_NAME(factory);
651 klass = gst_element_factory_get_metadata(factory, GST_ELEMENT_METADATA_KLASS);
653 ms_debug("Decodebin: found new element [%s] to link [%s]", factory_name, klass);
655 if (ms_streamer->ini.exclude_elem_names) {
656 /* Search if such plugin must be excluded */
657 for (index = 0; ms_streamer->ini.exclude_elem_names[index]; ++index) {
658 if (g_strrstr(factory_name, ms_streamer->ini.exclude_elem_names[index])) {
659 ms_debug("Decodebin: skipping [%s] as excluded", factory_name);
662 return GST_AUTOPLUG_SELECT_SKIP;
668 if (ms_streamer->ini.resource_required_elem_names) {
669 /* Try to acquire resources before adding element */
670 for (index = 0; ms_streamer->ini.resource_required_elem_names[index]; ++index) {
671 if (g_strrstr(factory_name, ms_streamer->ini.resource_required_elem_names[index])) {
672 ms_debug("Decodebin: trying to acquire resource for [%s] element", factory_name);
674 if (MM_RESOURCE_MANAGER_ERROR_NONE !=
675 mm_resource_manager_mark_for_acquire(ms_streamer->resource_manager,
676 MM_RESOURCE_MANAGER_RES_TYPE_VIDEO_DECODER,
677 MM_RESOURCE_MANAGER_RES_VOLUME_FULL,
678 &ms_streamer->video_decoder_resource)) {
679 ms_error("Failed to mark resources for acquire in [%s] element", factory_name);
680 return GST_AUTOPLUG_SELECT_SKIP;
683 if (MM_RESOURCE_MANAGER_ERROR_NONE !=
684 mm_resource_manager_commit(ms_streamer->resource_manager)) {
685 ms_error("Failed to acquire resources for [%s] element", factory_name);
687 if (MM_RESOURCE_MANAGER_ERROR_NONE !=
688 mm_resource_manager_mark_for_release(
689 ms_streamer->resource_manager,
690 ms_streamer->video_decoder_resource))
691 ms_error("Failed to mark resources for release in [%s] element", factory_name);
693 return GST_AUTOPLUG_SELECT_SKIP;
704 static gint __pad_type_compare(gconstpointer a, gconstpointer b)
706 GstPad *a_pad = NULL;
707 GstPad *b_pad = NULL;
708 const gchar *a_pad_type = NULL;
709 const gchar *b_pad_type = NULL;
713 ms_retvm_if(!a, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "a is NULL");
714 ms_retvm_if(!b, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "b is NULL");
719 a_pad_type = ms_get_pad_type(a_pad);
720 b_pad_type = ms_get_pad_type(b_pad);
724 if (MS_ELEMENT_IS_TEXT(a_pad_type))
726 else if (MS_ELEMENT_IS_TEXT(b_pad_type))
732 static void __decodebin_pad_added_cb(GstElement *element, GstPad *new_pad, gpointer user_data)
734 media_streamer_s *ms_streamer = (media_streamer_s *) user_data;
738 ms_retm_if(new_pad == NULL, "new_pad is NULL");
739 ms_retm_if(ms_streamer == NULL, "user_data is NULL");
741 g_mutex_lock(&ms_streamer->mutex_lock);
743 g_object_ref(new_pad);
745 ms_streamer->pads_types_list = g_list_insert_sorted(ms_streamer->pads_types_list, new_pad, __pad_type_compare);
747 g_mutex_unlock(&ms_streamer->mutex_lock);
752 static void __decodebin_nomore_pads_combine(GstPad *src_pad, media_streamer_s *ms_streamer, media_streamer_sink_bin_type_e sink_bin_type)
754 GstElement *found_element = NULL;
755 const gchar *new_pad_type = NULL;
756 GstCaps *caps = NULL;
757 gchar *caps_str = NULL;
761 ms_retm_if(src_pad == NULL, "src_pad is NULL");
762 ms_retm_if(ms_streamer == NULL, "ms_streamer is NULL");
764 found_element = gst_pad_get_parent_element(src_pad);
765 new_pad_type = ms_get_pad_type(src_pad);
767 if (MS_ELEMENT_IS_VIDEO(new_pad_type)) {
768 if (__ms_bin_find_element_and_link_by_type(found_element, src_pad, ms_streamer->transform_bin,
769 ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY))) {
770 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY);
773 if (sink_bin_type == MEDIA_STREAMER_SINK_BIN_RTP_SERVER) {
774 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER);
775 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_PAY);
776 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_RTP);
777 } else if (sink_bin_type == MEDIA_STREAMER_SINK_BIN_ADAPTIVE) {
778 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER);
779 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_MUXER);
780 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK);
782 caps = gst_pad_query_caps(src_pad, NULL);
783 caps_str = gst_caps_to_string(caps);
784 if (caps_str && (g_strrstr(caps_str, "ST12") || g_strrstr(caps_str, "SN12") ||
785 g_strrstr(caps_str, "SN21") || g_strrstr(caps_str, "S420") || g_strrstr(caps_str, "SR32"))) {
786 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK);
788 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_CONVERTER);
789 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK);
791 MS_SAFE_GFREE(caps_str);
792 gst_caps_unref(caps);
794 } else if (MS_ELEMENT_IS_AUDIO(new_pad_type)) {
795 if (sink_bin_type == MEDIA_STREAMER_SINK_BIN_RTP_SERVER) {
796 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER);
797 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_PAY);
798 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_RTP);
799 } else if (sink_bin_type == MEDIA_STREAMER_SINK_BIN_ADAPTIVE) {
800 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER);
801 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_MUXER);
802 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK);
804 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_CONVERTER);
805 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK);
807 } else if (MS_ELEMENT_IS_TEXT(new_pad_type)) {
808 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY);
810 ms_error("Unsupported pad type [%s]!", new_pad_type);
813 ms_generate_dots(ms_streamer->pipeline, "after_sink_linked");
814 gst_object_unref(found_element);
819 static void __decodebin_nomore_pads_cb(GstElement *decodebin, gpointer user_data)
821 media_streamer_s *ms_streamer = (media_streamer_s *) user_data;
822 media_streamer_sink_bin_type_e sink_bin_type = MEDIA_STREAMER_SINK_BIN_NORMAL;
823 media_streamer_node_s *rtp_node = NULL;
824 media_streamer_node_s *adaptive_sink = NULL;
825 char *decodebin_name = NULL;
826 char *param_value = NULL;
827 GList *iterator = NULL;
829 GstPad *src_pad = NULL;
833 ms_retm_if(decodebin == NULL, "decodebin is NULL");
834 ms_retm_if(ms_streamer == NULL, "user_data is NULL");
836 g_mutex_lock(&ms_streamer->mutex_lock);
838 rtp_node = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "rtp_container");
839 adaptive_sink = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "adaptive_sink");
842 g_object_get(G_OBJECT(decodebin), "name", &decodebin_name, NULL);
844 /* FIXME: This case may be not general */
845 if (g_strrstr(decodebin_name, MEDIASTREAMER_DECODEBIN_TYPE_DECODER)) {
846 sink_bin_type = MEDIA_STREAMER_SINK_BIN_NORMAL;
847 MS_SAFE_FREE(decodebin_name);
849 /* It`s server part of Streaming Scenario*/
850 media_streamer_node_get_param(rtp_node, MEDIA_STREAMER_PARAM_VIDEO_OUT_PORT, ¶m_value);
851 if (param_value && (strtol(param_value, NULL, 10) > 0))
852 sink_bin_type = MEDIA_STREAMER_SINK_BIN_RTP_SERVER;
854 MS_SAFE_FREE(param_value);
856 } else if (adaptive_sink) {
857 __ms_adaptive_sink_prepare(ms_streamer);
858 sink_bin_type = MEDIA_STREAMER_SINK_BIN_ADAPTIVE;
862 list = ms_streamer->pads_types_list;
863 for (iterator = list; iterator; iterator = iterator->next) {
864 src_pad = GST_PAD(iterator->data);
865 __decodebin_nomore_pads_combine(src_pad, ms_streamer, sink_bin_type);
868 g_mutex_unlock(&ms_streamer->mutex_lock);
873 static GstElement *__ms_decodebin_create(media_streamer_s *ms_streamer, char *name)
875 GstElement *decodebin = NULL;
879 ms_retvm_if(!ms_streamer, NULL, "ms_streamer is NULL");
881 decodebin = ms_element_create(DEFAULT_DECODEBIN, name);
882 ms_bin_add_element(ms_streamer->transform_bin, decodebin, TRUE);
883 gst_element_sync_state_with_parent(decodebin);
885 ms_signal_create(&ms_streamer->autoplug_sig_list, decodebin, "pad-added", G_CALLBACK(__decodebin_pad_added_cb), ms_streamer);
886 ms_signal_create(&ms_streamer->autoplug_sig_list, decodebin, "autoplug-select", G_CALLBACK(__decodebin_autoplug_select_cb), ms_streamer);
887 ms_signal_create(&ms_streamer->autoplug_sig_list, decodebin, "no-more-pads", G_CALLBACK(__decodebin_nomore_pads_cb), ms_streamer);
895 static gboolean __ms_sink_bin_prepare(media_streamer_s *ms_streamer, GstPad *src_pad, const gchar *src_pad_type)
897 GstElement *decoder_element = NULL;
898 GstElement *found_element = NULL;
899 GstElement *parent_rtp_element = NULL;
903 ms_retvm_if(!ms_streamer, FALSE, "ms_streamer is NULL");
904 ms_retvm_if(!src_pad, FALSE, "src_pad is NULL");
906 /* Getting Depayloader */
907 parent_rtp_element = gst_pad_get_parent_element(src_pad);
909 if (MS_ELEMENT_IS_VIDEO(src_pad_type)) {
910 gst_object_ref(parent_rtp_element);
911 found_element = ms_combine_next_element(parent_rtp_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_DEPAY);
912 decoder_element = __ms_bin_find_element_and_link_by_type(found_element, NULL, ms_streamer->transform_bin,
913 ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER));
915 if (!decoder_element) {
916 if (ms_streamer->ini.use_decodebin) {
917 decoder_element = __ms_decodebin_create(ms_streamer, MEDIASTREAMER_DECODEBIN_TYPE_DECODER);
918 gst_object_ref(found_element);
919 __ms_link_two_elements(found_element, NULL, decoder_element);
920 MS_SAFE_UNREF(decoder_element);
926 gst_object_ref(found_element);
927 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER);
928 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK);
931 __ms_link_two_elements(found_element, NULL, decoder_element);
932 found_element = ms_combine_next_element(decoder_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK);
934 } else if (MS_ELEMENT_IS_AUDIO(src_pad_type)) {
935 gst_object_ref(parent_rtp_element);
936 found_element = ms_combine_next_element(parent_rtp_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_DEPAY);
937 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER);
938 found_element = ms_combine_next_element(found_element, NULL, ms_streamer->sink_bin, MEDIA_STREAMER_NODE_TYPE_SINK);
940 ms_info("Unknown media type received from rtp element!");
942 MS_SAFE_UNREF(found_element);
943 MS_SAFE_UNREF(parent_rtp_element);
950 void ms_rtpbin_pad_added_cb(GstElement *src, GstPad *new_pad, gpointer user_data)
952 media_streamer_s *ms_streamer = NULL;
953 GstPad *target_pad = NULL;
954 GstCaps *src_pad_caps = NULL;
955 gchar *src_pad_name = NULL;
956 GstStructure *src_pad_struct = NULL;
957 const gchar *src_pad_type = NULL;
958 GstPad *src_pad = NULL;
959 media_streamer_node_s *ms_node = (media_streamer_node_s *) user_data;
963 ms_retm_if(new_pad == NULL, "new_pad is NULL");
964 ms_retm_if(ms_node == NULL, "ms_node is NULL");
965 ms_debug("Pad [%s] added on [%s]", GST_PAD_NAME(new_pad), GST_ELEMENT_NAME(src));
967 if (g_str_has_prefix(GST_PAD_NAME(new_pad), "recv_rtp_src")) {
968 ms_streamer = ms_node->parent_streamer;
969 ms_retm_if(ms_streamer == NULL, "Node's parent streamer handle is NULL");
970 g_mutex_lock(&ms_streamer->mutex_lock);
972 target_pad = gst_ghost_pad_get_target(GST_GHOST_PAD(new_pad));
973 src_pad_caps = gst_pad_query_caps(target_pad, NULL);
974 src_pad_struct = gst_caps_get_structure(src_pad_caps, 0);
975 src_pad_type = gst_structure_get_string(src_pad_struct, "media");
976 ms_debug("type is [%s]", src_pad_type);
978 if (MS_ELEMENT_IS_VIDEO(src_pad_type))
979 src_pad_name = g_strdup_printf("%s_out", "video");
980 else if (MS_ELEMENT_IS_AUDIO(src_pad_type))
981 src_pad_name = g_strdup_printf("%s_out", "audio");
983 if (src_pad_name != NULL) {
985 src_pad = gst_element_get_static_pad(ms_node->gst_element, src_pad_name);
988 gst_ghost_pad_set_target(GST_GHOST_PAD(src_pad), new_pad);
990 if (src_pad && __ms_sink_bin_prepare(ms_streamer, src_pad, src_pad_type)) {
991 ms_element_set_state(ms_node->gst_element, GST_STATE_PLAYING);
992 ms_generate_dots(ms_streamer->pipeline, "rtpbin_playing");
994 ms_error("Failed to prepare sink_bin for pad type [%s]", src_pad_type);
997 MS_SAFE_GFREE(src_pad_name);
999 g_mutex_unlock(&ms_node->parent_streamer->mutex_lock);
1001 gst_caps_unref(src_pad_caps);
1002 MS_SAFE_UNREF(target_pad);
1009 void ms_demux_pad_added_cb(GstElement *element, GstPad *new_pad, gpointer user_data)
1011 media_streamer_s *ms_streamer = (media_streamer_s *)user_data;
1015 ms_retm_if(ms_streamer == NULL, "user_data is NULL");
1016 ms_retm_if(new_pad == NULL, "new_pad is NULL");
1018 g_mutex_lock(&ms_streamer->mutex_lock);
1020 g_object_ref(new_pad);
1022 ms_streamer->pads_types_list = g_list_insert_sorted(ms_streamer->pads_types_list, new_pad, __pad_type_compare);
1024 g_mutex_unlock(&ms_streamer->mutex_lock);
1029 void ms_hlsdemux_pad_added_cb(GstElement *element, GstPad *new_pad, gpointer user_data)
1035 gp = GST_PAD(user_data);
1036 gst_ghost_pad_set_target(GST_GHOST_PAD(gp), new_pad);
1041 static void __demux_nomore_pads_combine(GstPad *src_pad, media_streamer_s *ms_streamer)
1043 GstElement *found_element = NULL;
1044 const gchar *new_pad_type = NULL;
1048 found_element = gst_pad_get_parent_element(src_pad);
1049 new_pad_type = ms_get_pad_type(src_pad);
1051 if (MS_ELEMENT_IS_VIDEO(new_pad_type))
1052 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER);
1053 else if (MS_ELEMENT_IS_AUDIO(new_pad_type))
1054 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER);
1055 else if (MS_ELEMENT_IS_TEXT(new_pad_type))
1056 found_element = ms_combine_next_element(found_element, src_pad, ms_streamer->transform_bin, MEDIA_STREAMER_NODE_TYPE_TEXT_OVERLAY);
1058 ms_error("Unsupported pad type [%s]!", new_pad_type);
1060 ms_generate_dots(ms_streamer->pipeline, "after_demux_linked");
1061 gst_object_unref(found_element);
1066 void ms_demux_nomore_pads_cb(GstElement *element, gpointer user_data)
1068 media_streamer_s *ms_streamer = (media_streamer_s *) user_data;
1069 GList *iterator = NULL;
1074 ms_retm_if(ms_streamer == NULL, "Handle is NULL");
1076 g_mutex_lock(&ms_streamer->mutex_lock);
1078 list = ms_streamer->pads_types_list;
1079 for (iterator = list; iterator; iterator = iterator->next) {
1080 GstPad *src_pad = GST_PAD(iterator->data);
1081 __demux_nomore_pads_combine(src_pad, ms_streamer);
1084 g_mutex_unlock(&ms_streamer->mutex_lock);
1089 int ms_element_set_state(GstElement *element, GstState state)
1091 GstStateChangeReturn ret_state;
1095 ms_retvm_if(element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "element is NULL");
1097 ret_state = gst_element_set_state(element, state);
1099 if (ret_state == GST_STATE_CHANGE_FAILURE) {
1100 ms_error("Failed to set element [%s] into %s state", GST_ELEMENT_NAME(element), gst_element_state_get_name(state));
1101 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
1106 return MEDIA_STREAMER_ERROR_NONE;
1109 GstElement *ms_element_create(const char *plugin_name, const char *name)
1111 GstElement *plugin_elem = NULL;
1115 ms_retvm_if(plugin_name == NULL, (GstElement *) NULL, "Error empty plugin name");
1117 ms_info("Creating [%s] element", plugin_name);
1119 plugin_elem = gst_element_factory_make(plugin_name, name);
1120 ms_retvm_if(plugin_elem == NULL, (GstElement *) NULL, "Error creating element [%s]", plugin_name);
1127 static int __ms_adaptive_sink_prepare(media_streamer_s *ms_streamer)
1129 static node_info_s nodes_info[] = {
1130 {"Codec/Encoder/Video", "video_encoder"}, /* MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER */
1131 {"Codec/Encoder/Audio", "audio_encoder"}, /* MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER */
1132 {"Codec/Muxer", "mpegtsmux"}, /* MEDIA_STREAMER_NODE_TYPE_MUXER */
1135 GstCaps *video_enc_src_caps = NULL;
1136 GstCaps *video_enc_sink_caps = NULL;
1137 GstCaps *audio_enc_src_caps = NULL;
1138 GstCaps *audio_enc_sink_caps = NULL;
1139 GstElement *audio_enc = NULL;
1140 GstElement *video_enc = NULL;
1141 GstCaps *muxer_src_caps = NULL;
1142 GstElement *muxer = NULL;
1143 node_plug_s video_enc_plug_info = {0, };
1144 node_plug_s audio_enc_plug_info = {0, };
1145 node_plug_s mux_plug_info = {0, };
1149 ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer is NULL");
1151 video_enc_src_caps = gst_caps_new_simple("video/mpeg", "mpegversion", G_TYPE_INT, 4, NULL);
1152 video_enc_sink_caps = gst_caps_new_empty_simple("video/x-raw");
1153 video_enc_plug_info.info = &(nodes_info[0]);
1154 video_enc_plug_info.src_caps = video_enc_src_caps;
1155 video_enc_plug_info.sink_caps = video_enc_sink_caps;
1156 video_enc = ms_node_element_create(&video_enc_plug_info, MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER);
1158 audio_enc_src_caps = gst_caps_new_simple("audio/mpeg", "mpegversion", G_TYPE_INT, 4, NULL);
1159 audio_enc_sink_caps = gst_caps_new_empty_simple("audio/x-raw");
1160 audio_enc_plug_info.info = &(nodes_info[1]);
1161 audio_enc_plug_info.src_caps = audio_enc_src_caps;
1162 audio_enc_plug_info.sink_caps = audio_enc_sink_caps;
1163 audio_enc = ms_node_element_create(&audio_enc_plug_info, MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER);
1165 muxer_src_caps = gst_caps_new_empty_simple("video/mpegts");
1166 mux_plug_info.info = &(nodes_info[2]);
1167 mux_plug_info.src_caps = muxer_src_caps;
1168 muxer = ms_node_element_create(&mux_plug_info, MEDIA_STREAMER_NODE_TYPE_MUXER);
1170 ms_bin_add_element(ms_streamer->transform_bin, muxer, FALSE);
1171 gst_element_sync_state_with_parent(muxer);
1172 ms_bin_add_element(ms_streamer->transform_bin, video_enc, FALSE);
1173 gst_element_sync_state_with_parent(video_enc);
1174 ms_bin_add_element(ms_streamer->transform_bin, audio_enc, FALSE);
1175 gst_element_sync_state_with_parent(audio_enc);
1179 return MEDIA_STREAMER_ERROR_NONE;
1182 GstElement *ms_adaptive_element_create(void)
1184 GstElement *adaptive_bin = NULL;
1188 adaptive_bin = gst_bin_new("adaptive_src");
1189 ms_retvm_if(!adaptive_bin, (GstElement *) NULL, "Error: creating elements for adaptive source");
1191 ms_add_no_target_ghostpad(adaptive_bin, "src", GST_PAD_SRC);
1193 /* Add adaptive node parameters as GObject data with destroy function */
1194 MS_SET_INT_STATIC_STRING_PARAM(adaptive_bin, MEDIA_STREAMER_PARAM_URI, "http://localhost");
1198 return adaptive_bin;
1202 static gboolean __ms_feature_node_filter(GstPluginFeature *feature, gpointer data)
1204 node_plug_s *plug_info = (node_plug_s*)data;
1205 gboolean can_accept = FALSE;
1206 gboolean src_can_accept = FALSE;
1207 gboolean sink_can_accept = FALSE;
1208 GstElementFactory *factory = NULL;
1209 const gchar *factory_klass = NULL;
1211 if (!GST_IS_ELEMENT_FACTORY(feature))
1214 factory = GST_ELEMENT_FACTORY(feature);
1215 factory_klass = gst_element_factory_get_klass(factory);
1217 if (plug_info && g_strrstr(factory_klass, plug_info->info->klass_name)) {
1218 if (GST_IS_CAPS(plug_info->src_caps))
1219 src_can_accept = gst_element_factory_can_src_any_caps(factory, plug_info->src_caps);
1221 if (GST_IS_CAPS(plug_info->sink_caps))
1222 sink_can_accept = gst_element_factory_can_sink_any_caps(factory, plug_info->sink_caps);
1224 if (GST_IS_CAPS(plug_info->src_caps) && GST_IS_CAPS(plug_info->sink_caps)) {
1225 if (src_can_accept && sink_can_accept)
1227 } else if (src_can_accept || sink_can_accept)
1232 for ( ; plug_info->exclude_names && plug_info->exclude_names[index]; ++index) {
1233 if (g_strrstr(GST_OBJECT_NAME(factory), plug_info->exclude_names[index])) {
1234 ms_debug("Skipping compatible factory [%s] as excluded.", GST_OBJECT_NAME(factory));
1239 ms_info("[INFO] Found compatible factory [%s] for klass [%s]",
1240 GST_OBJECT_NAME(factory), factory_klass);
1249 static GstElement *ms_element_create_from_ini(node_plug_s *plug_info, media_streamer_node_type_e type)
1251 const gchar *src_type, *sink_type;
1252 const gchar *format_type;
1253 GstElement *gst_element = NULL;
1254 gchar conf_key[INI_MAX_STRLEN] = {0,};
1255 gchar *plugin_name = NULL;
1259 ms_retvm_if(plug_info == NULL, NULL, "plug_info is NULL");
1261 MS_GET_CAPS_TYPE(plug_info->src_caps, src_type);
1262 MS_GET_CAPS_TYPE(plug_info->sink_caps, sink_type);
1264 ms_info("Specified node formats types: in[%s] - out[%s]", sink_type, src_type);
1266 if (type == MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER) {
1267 format_type = src_type;
1269 MS_GET_CAPS_TYPE(gst_caps_from_string(MEDIA_STREAMER_DEFAULT_VIDEO_FORMAT), format_type);
1270 } else if (type == MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER) {
1271 format_type = src_type;
1273 MS_GET_CAPS_TYPE(gst_caps_from_string(MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT), format_type);
1274 } else if (type == MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER) {
1275 format_type = sink_type;
1277 MS_GET_CAPS_TYPE(gst_caps_from_string(MEDIA_STREAMER_DEFAULT_VIDEO_FORMAT), format_type);
1278 } else if (type == MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER) {
1279 format_type = sink_type;
1281 MS_GET_CAPS_TYPE(gst_caps_from_string(MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT), format_type);
1283 format_type = sink_type ? sink_type : src_type;
1285 if (snprintf(conf_key, INI_MAX_STRLEN, "node type %d:%s", type, format_type) >= INI_MAX_STRLEN) {
1286 ms_error("Failed to generate config field name, size >= %d", INI_MAX_STRLEN);
1290 plugin_name = ms_ini_get_string(conf_key, NULL);
1293 gst_element = ms_element_create(plugin_name, NULL);
1294 MS_SAFE_GFREE(plugin_name);
1302 static GstElement *ms_element_create_by_registry(node_plug_s *plug_info, media_streamer_node_type_e type)
1304 GstElement *gst_element = NULL;
1305 const gchar *src_type = NULL;
1306 const gchar *sink_type = NULL;
1307 GList *factories = NULL;
1308 GstElementFactory *factory = NULL;
1312 ms_retvm_if(plug_info == NULL, NULL, "plug_info is NULL");
1314 MS_GET_CAPS_TYPE(plug_info->src_caps, src_type);
1315 MS_GET_CAPS_TYPE(plug_info->sink_caps, sink_type);
1317 ms_ini_read_list("general:exclude elements", &plug_info->exclude_names);
1319 factories = gst_registry_feature_filter(gst_registry_get(),
1320 __ms_feature_node_filter, FALSE, plug_info);
1321 factories = g_list_sort(factories, (GCompareFunc) __ms_factory_rank_compare);
1324 factory = GST_ELEMENT_FACTORY(factories->data);
1325 ms_info("Sorted result element is [%s]", GST_OBJECT_NAME(factory));
1326 gst_element = ms_element_create(GST_OBJECT_NAME(factory), NULL);
1328 ms_debug("Could not find any compatible element for node [%d]: in[%s] - out[%s]",
1329 type, sink_type, src_type);
1332 g_strfreev(plug_info->exclude_names);
1333 gst_plugin_list_free(factories);
1340 static GstElement *__ms_video_encoder_element_create(node_plug_s *plug_info)
1342 GstElement *video_scale = NULL;
1343 GstElement *video_convert = NULL;
1344 GstElement *encoder_elem = NULL;
1345 GstElement *encoder_parser = NULL;
1346 GstElement *encoder_bin = NULL;
1347 gboolean gst_ret = FALSE;
1348 gboolean use_zerocopy = FALSE;
1349 const gchar *src_type = NULL;
1350 node_plug_s encoder_info = {0,};
1351 node_plug_s parser_info = {0,};
1352 node_info_s node_info = {MEDIA_STREAMER_PARSER_KLASS, DEFAULT_VIDEO_PARSER};
1353 media_format_mimetype_e encoder_type = MEDIA_FORMAT_MAX;
1354 GstCaps *enc_caps = NULL;
1358 ms_retvm_if(plug_info == NULL, NULL, "plug_info is NULL");
1360 enc_caps = plug_info->src_caps;
1362 enc_caps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_VIDEO_FORMAT);
1363 ms_debug("No Video encoding format is set! Default will be: [%s]", MEDIA_STREAMER_DEFAULT_VIDEO_FORMAT);
1367 /* Creating Video Encoder */
1368 encoder_info.info = ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER);
1369 encoder_info.src_caps = enc_caps;
1370 encoder_info.sink_caps = plug_info->sink_caps;
1371 encoder_info.exclude_names = NULL;
1373 encoder_elem = ms_element_create_from_ini(&encoder_info, MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER);
1375 encoder_elem = ms_element_create_by_registry(&encoder_info, MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER);
1377 /* Creating bin - Video Encoder */
1378 encoder_bin = gst_bin_new("video_encoder");
1380 if (!encoder_elem || !encoder_bin)
1383 use_zerocopy = ms_ini_get_boolean("general:use zerocopy", DEFAULT_USE_ZEROCOPY);
1385 ms_info("Video encoder uses zerocopy");
1386 gst_bin_add(GST_BIN(encoder_bin), encoder_elem);
1387 __ms_add_ghostpad(encoder_elem, "src", encoder_bin, "src");
1388 __ms_add_ghostpad(encoder_elem, "sink", encoder_bin, "sink");
1394 /* Creating Scaler, Converter */
1395 video_scale = ms_element_create(DEFAULT_VIDEO_SCALE, NULL);
1396 video_convert = ms_element_create(DEFAULT_VIDEO_CONVERT, NULL);
1398 if (!video_convert || !video_scale) {
1402 MS_GET_CAPS_TYPE(enc_caps, src_type);
1403 encoder_type = ms_convert_video_string_format_to_media_format(src_type);
1405 if (encoder_type == MEDIA_FORMAT_VP8) {
1406 /* VP8 does not have parser */
1407 g_object_set(G_OBJECT(encoder_elem), "deadline", 1, NULL);
1409 /* Adding elements to bin Video Encoder */
1410 gst_bin_add_many(GST_BIN(encoder_bin), video_convert, video_scale, encoder_elem, NULL);
1411 gst_ret = gst_element_link_many(video_convert, video_scale, encoder_elem, NULL);
1412 if (gst_ret != TRUE) {
1413 ms_error("Failed to link elements into encoder_bin");
1414 MS_SAFE_UNREF(encoder_bin);
1417 __ms_add_ghostpad(encoder_elem, "src", encoder_bin, "src");
1419 /* Creating Video Parser */
1420 parser_info.info = &node_info;
1421 parser_info.src_caps = enc_caps;
1422 parser_info.sink_caps = enc_caps;
1423 parser_info.exclude_names = NULL;
1425 encoder_parser = ms_element_create_from_ini(&parser_info, MEDIA_STREAMER_NODE_TYPE_PARSER);
1426 if (!encoder_parser)
1427 encoder_parser = ms_element_create_by_registry(&parser_info, MEDIA_STREAMER_NODE_TYPE_PARSER);
1428 if (!encoder_parser)
1431 /* Settings if H264 format is set*/
1432 if (encoder_type == MEDIA_FORMAT_H264_SP) {
1433 g_object_set(GST_OBJECT(encoder_parser), "config-interval", H264_PARSER_CONFIG_INTERVAL, NULL);
1434 g_object_set(G_OBJECT(encoder_elem), "tune", H264_ENCODER_ZEROLATENCY, NULL);
1435 g_object_set(G_OBJECT(encoder_elem), "byte-stream", TRUE, NULL);
1436 g_object_set(G_OBJECT(encoder_elem), "bitrate", 3000, NULL);
1437 g_object_set(G_OBJECT(encoder_elem), "threads", 2, NULL);
1440 /* Adding elements to bin Video Encoder */
1441 gst_bin_add_many(GST_BIN(encoder_bin), video_convert, video_scale, encoder_elem, encoder_parser, NULL);
1442 gst_ret = gst_element_link_many(video_convert, video_scale, encoder_elem, encoder_parser, NULL);
1443 if (gst_ret != TRUE) {
1444 ms_error("Failed to link elements into encoder_bin");
1445 MS_SAFE_UNREF(encoder_bin);
1448 __ms_add_ghostpad(encoder_parser, "src", encoder_bin, "src");
1450 __ms_add_ghostpad(video_convert, "sink", encoder_bin, "sink");
1457 ms_error("Error: creating elements for video encoder bin");
1458 MS_SAFE_UNREF(video_convert);
1459 MS_SAFE_UNREF(video_scale);
1460 MS_SAFE_UNREF(encoder_elem);
1461 MS_SAFE_UNREF(encoder_parser);
1462 MS_SAFE_UNREF(encoder_bin);
1469 static GstElement *__ms_video_decoder_element_create(node_plug_s *plug_info)
1471 gboolean is_hw_codec = FALSE;
1472 GstElement *last_elem = NULL;
1473 GstElement *decoder_elem = NULL;
1474 GstElement *decoder_parser = NULL;
1475 GstElement *decoder_queue = NULL;
1476 GstElement *video_conv = NULL;
1477 GstElement *video_scale = NULL;
1478 GstElement *decoder_bin = NULL;
1479 node_plug_s decoder_info = {0,};
1480 node_plug_s parser_info = {0,};
1481 node_info_s nodes_info = {MEDIA_STREAMER_PARSER_KLASS, DEFAULT_VIDEO_PARSER};
1482 media_format_mimetype_e decoder_type = MEDIA_FORMAT_MAX;
1483 gboolean gst_ret = FALSE;
1484 const gchar *sink_type = NULL;
1485 GstCaps *dec_caps = NULL;
1486 gchar *codec_name = NULL;
1490 ms_retvm_if(plug_info == NULL, NULL, "plug_info is NULL");
1492 dec_caps = plug_info->sink_caps;
1494 dec_caps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_VIDEO_FORMAT);
1495 ms_debug("No Video decoding format is set! Default will be: [%s]", MEDIA_STREAMER_DEFAULT_VIDEO_FORMAT);
1498 /* Creating Video Decoder */
1499 decoder_info.info = ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER);
1500 decoder_info.src_caps = plug_info->src_caps;
1501 decoder_info.sink_caps = dec_caps;
1502 decoder_info.exclude_names = NULL;
1504 decoder_elem = ms_element_create_from_ini(&decoder_info, MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER);
1506 decoder_elem = ms_element_create_by_registry(&decoder_info, MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER);
1508 /* Creating Video Parser */
1509 parser_info.info = &nodes_info;
1510 parser_info.src_caps = dec_caps;
1511 parser_info.sink_caps = dec_caps;
1512 parser_info.exclude_names = NULL;
1514 decoder_parser = ms_element_create_from_ini(&parser_info, MEDIA_STREAMER_NODE_TYPE_PARSER);
1515 if (!decoder_parser)
1516 decoder_parser = ms_element_create_by_registry(&parser_info, MEDIA_STREAMER_NODE_TYPE_PARSER);
1518 /* Settings if H264 format is set*/
1519 MS_GET_CAPS_TYPE(dec_caps, sink_type);
1520 decoder_type = ms_convert_video_string_format_to_media_format(sink_type);
1521 if (decoder_type == MEDIA_FORMAT_H264_SP)
1522 g_object_set(G_OBJECT(decoder_parser), "config-interval", H264_PARSER_CONFIG_INTERVAL, NULL);
1524 /* Creating bin - Video Decoder */
1525 decoder_queue = ms_element_create("queue", NULL);
1526 decoder_bin = gst_bin_new("video_decoder");
1528 if (!decoder_elem || !decoder_queue || !decoder_parser || !decoder_bin) {
1529 ms_error("Error: creating elements for video decoder bin");
1533 codec_name = GST_OBJECT_NAME(decoder_elem);
1534 if (g_strrstr(codec_name, "omx") || g_strrstr(codec_name, "sprd"))
1537 /* Adding elements to bin Audio Encoder */
1538 gst_bin_add_many(GST_BIN(decoder_bin), decoder_queue, decoder_elem, decoder_parser, NULL);
1539 gst_ret = gst_element_link_many(decoder_queue, decoder_parser, decoder_elem, NULL);
1540 if (gst_ret != TRUE) {
1541 ms_error("Failed to link elements into decoder_bin");
1542 MS_SAFE_UNREF(decoder_bin);
1546 last_elem = decoder_elem;
1549 video_conv = ms_element_create("videoconvert", NULL);
1550 video_scale = ms_element_create("videoscale", NULL);
1551 if (!video_conv || !video_scale) {
1552 ms_error("Error: creating elements for video decoder bin");
1556 gst_bin_add_many(GST_BIN(decoder_bin), video_conv, video_scale, NULL);
1557 gst_ret = gst_element_link_many(decoder_elem, video_conv, video_scale, NULL);
1558 if (gst_ret != TRUE) {
1559 ms_error("Failed to link elements into decoder_bin");
1560 MS_SAFE_UNREF(decoder_bin);
1563 last_elem = video_scale;
1566 __ms_add_ghostpad(last_elem, "src", decoder_bin, "src");
1567 __ms_add_ghostpad(decoder_queue, "sink", decoder_bin, "sink");
1575 MS_SAFE_UNREF(decoder_elem);
1576 MS_SAFE_UNREF(decoder_queue);
1577 MS_SAFE_UNREF(decoder_parser);
1578 MS_SAFE_UNREF(video_conv);
1579 MS_SAFE_UNREF(video_scale);
1580 MS_SAFE_UNREF(decoder_bin);
1587 static GstElement *__ms_audio_encoder_element_create(node_plug_s *plug_info)
1589 gboolean gst_ret = FALSE;
1590 GstElement *audio_convert = NULL;
1591 GstElement *audio_resample = NULL;
1592 GstElement *audio_filter = NULL;
1593 GstElement *audio_postenc_convert = NULL;
1594 GstElement *audio_encoder = NULL;
1595 GstElement *audio_enc_bin = NULL;
1596 node_plug_s plug_info_encoder = {0,};
1597 gchar *encoder_name = NULL;
1598 GstCaps *audioCaps = NULL;
1599 GstCaps *enc_caps = NULL;
1603 ms_retvm_if(plug_info == NULL, NULL, "plug_info is NULL");
1605 enc_caps = plug_info->src_caps;
1607 enc_caps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT);
1608 ms_debug("No Audio encoding format is set! Default will be: [%s]", MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT);
1611 /* Creating Converter, Resampler, Filter */
1612 audio_convert = ms_element_create(DEFAULT_AUDIO_CONVERT, NULL);
1613 audio_resample = ms_element_create(DEFAULT_AUDIO_RESAMPLE, NULL);
1614 audio_filter = ms_element_create(DEFAULT_FILTER, NULL);
1615 audio_postenc_convert = ms_element_create(DEFAULT_AUDIO_CONVERT, NULL);
1617 /* Creating Audio Encoder */
1618 plug_info_encoder.info = ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER);
1619 plug_info_encoder.src_caps = enc_caps;
1620 plug_info_encoder.sink_caps = plug_info->sink_caps;
1621 plug_info_encoder.exclude_names = NULL;
1623 audio_encoder = ms_element_create_from_ini(&plug_info_encoder, MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER);
1625 audio_encoder = ms_element_create_by_registry(&plug_info_encoder, MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER);
1627 encoder_name = gst_element_get_name(audio_encoder);
1628 if (encoder_name && g_strrstr(encoder_name, "aac"))
1629 g_object_set(audio_encoder, "compliance", -2, NULL);
1630 MS_SAFE_GFREE(encoder_name);
1632 /* Creating bin - Audio Encoder */
1633 audio_enc_bin = gst_bin_new("audio_encoder");
1634 if (!audio_convert || !audio_postenc_convert || !audio_filter || !audio_resample || !audio_encoder || !audio_enc_bin) {
1635 ms_error("Error: creating elements for audio encoder bin");
1639 audioCaps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_AUDIO_RAW_FORMAT);
1640 g_object_set(G_OBJECT(audio_filter), "caps", audioCaps, NULL);
1641 gst_caps_unref(audioCaps);
1643 /* Adding elements to bin Audio Encoder */
1644 gst_bin_add_many(GST_BIN(audio_enc_bin), audio_convert, audio_postenc_convert, audio_filter, audio_resample, audio_encoder, NULL);
1645 gst_ret = gst_element_link_many(audio_convert, audio_resample, audio_filter, audio_postenc_convert, audio_encoder, NULL);
1646 if (gst_ret != TRUE) {
1647 ms_error("Failed to link elements into decoder_bin");
1648 MS_SAFE_UNREF(audio_enc_bin);
1651 __ms_add_ghostpad(audio_encoder, "src", audio_enc_bin, "src");
1652 __ms_add_ghostpad(audio_convert, "sink", audio_enc_bin, "sink");
1656 return audio_enc_bin;
1660 MS_SAFE_UNREF(audio_convert);
1661 MS_SAFE_UNREF(audio_resample);
1662 MS_SAFE_UNREF(audio_postenc_convert);
1663 MS_SAFE_UNREF(audio_filter);
1664 MS_SAFE_UNREF(audio_encoder);
1665 MS_SAFE_UNREF(audio_enc_bin);
1673 static GstElement *__ms_audio_decoder_element_create(node_plug_s *plug_info)
1675 gboolean gst_ret = FALSE;
1676 GstElement *decoder_bin = NULL;
1677 GstElement *decoder_elem = NULL;
1678 GstElement *decoder_parser = NULL;
1679 GstElement *decoder_queue = NULL;
1680 GstElement *audio_conv = NULL;
1681 GstElement *audio_resample = NULL;
1682 node_plug_s decoder_info = {0,};
1683 node_plug_s parser_info = {0,};
1684 node_info_s nodes_info = {MEDIA_STREAMER_PARSER_KLASS, DEFAULT_AUDIO_PARSER};
1685 GstCaps *dec_caps = NULL;
1689 dec_caps = plug_info->sink_caps;
1691 dec_caps = gst_caps_from_string(MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT);
1692 ms_debug("No Audio decoding format is set! Default will be: [%s]", MEDIA_STREAMER_DEFAULT_AUDIO_FORMAT);
1695 /* Creating Audio Decoder */
1696 decoder_info.info = ms_node_get_klass_by_its_type(MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER);
1697 decoder_info.src_caps = plug_info->src_caps;
1698 decoder_info.sink_caps = dec_caps;
1699 decoder_info.exclude_names = NULL;
1701 decoder_elem = ms_element_create_from_ini(&decoder_info, MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER);
1703 decoder_elem = ms_element_create_by_registry(&decoder_info, MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER);
1705 /* Creating Audio Parser */
1706 parser_info.info = &nodes_info;
1707 parser_info.src_caps = dec_caps;
1708 parser_info.sink_caps = dec_caps;
1709 parser_info.exclude_names = NULL;
1711 decoder_parser = ms_element_create_from_ini(&parser_info, MEDIA_STREAMER_NODE_TYPE_PARSER);
1712 if (!decoder_parser)
1713 decoder_parser = ms_element_create_by_registry(&parser_info, MEDIA_STREAMER_NODE_TYPE_PARSER);
1715 /* Creating bin - Audio Decoder */
1716 decoder_bin = gst_bin_new("audio_decoder");
1717 decoder_queue = ms_element_create("queue", NULL);
1718 if (!decoder_elem || !decoder_queue || !decoder_parser || !decoder_bin) {
1719 ms_error("Error: creating elements for audio decoder bin");
1723 /* Adding elements to bin Audio Encoder */
1724 gst_bin_add_many(GST_BIN(decoder_bin), decoder_queue, decoder_elem, decoder_parser, NULL);
1725 gst_ret = gst_element_link_many(decoder_queue, decoder_parser, decoder_elem, NULL);
1726 if (gst_ret != TRUE) {
1727 ms_error("Failed to link elements into decoder_bin");
1728 MS_SAFE_UNREF(decoder_bin);
1732 audio_conv = ms_element_create("audioconvert", NULL);
1733 audio_resample = ms_element_create("audioresample", NULL);
1734 if (!audio_conv || !audio_resample) {
1735 ms_error("Error: creating elements for audio decoder bin");
1739 gst_bin_add_many(GST_BIN(decoder_bin), audio_conv, audio_resample, NULL);
1740 gst_ret = gst_element_link_many(decoder_elem, audio_conv, audio_resample, NULL);
1741 if (gst_ret != TRUE) {
1742 ms_error("Failed to link elements into decoder_bin");
1743 MS_SAFE_UNREF(decoder_bin);
1747 __ms_add_ghostpad(audio_resample, "src", decoder_bin, "src");
1748 __ms_add_ghostpad(decoder_queue, "sink", decoder_bin, "sink");
1756 MS_SAFE_UNREF(decoder_elem);
1757 MS_SAFE_UNREF(decoder_queue);
1758 MS_SAFE_UNREF(decoder_parser);
1759 MS_SAFE_UNREF(audio_conv);
1760 MS_SAFE_UNREF(audio_resample);
1761 MS_SAFE_UNREF(decoder_bin);
1768 GstElement *ms_node_element_create(node_plug_s *plug_info, media_streamer_node_type_e type)
1770 GstElement *gst_element = NULL;
1771 const gchar *src_type = NULL;
1772 const gchar *sink_type = NULL;
1776 ms_retvm_if(plug_info == NULL, NULL, "plug_info is NULL");
1778 MS_GET_CAPS_TYPE(plug_info->src_caps, src_type);
1779 MS_GET_CAPS_TYPE(plug_info->sink_caps, sink_type);
1781 /* 1. Main priority:
1782 * If Node klass defined as MEDIA_STREAMER_STRICT or ENCODER/DECODER or CONVERTER types,
1783 * element will be created immediately by format or name */
1784 if (type == MEDIA_STREAMER_NODE_TYPE_AUDIO_ENCODER)
1785 gst_element = __ms_audio_encoder_element_create(plug_info);
1786 else if (type == MEDIA_STREAMER_NODE_TYPE_AUDIO_DECODER)
1787 gst_element = __ms_audio_decoder_element_create(plug_info);
1788 else if (type == MEDIA_STREAMER_NODE_TYPE_VIDEO_ENCODER)
1789 gst_element = __ms_video_encoder_element_create(plug_info);
1790 else if (type == MEDIA_STREAMER_NODE_TYPE_VIDEO_DECODER)
1791 gst_element = __ms_video_decoder_element_create(plug_info);
1792 else if (type == MEDIA_STREAMER_NODE_TYPE_AUDIO_CONVERTER || type == MEDIA_STREAMER_NODE_TYPE_VIDEO_CONVERTER)
1793 gst_element = ms_element_create(plug_info->info->default_name, NULL);
1794 else if (g_strrstr(MEDIA_STREAMER_STRICT, plug_info->info->klass_name) || (!src_type && !sink_type)) {
1795 if (type == MEDIA_STREAMER_NODE_TYPE_RTP)
1796 gst_element = ms_rtp_element_create();
1797 else if (type == MEDIA_STREAMER_NODE_TYPE_WEBRTC)
1798 gst_element = ms_webrtc_element_create();
1800 gst_element = ms_element_create(plug_info->info->default_name, NULL);
1803 /* 2. Second priority:
1804 * Try to get plugin name that defined in ini file
1805 * according with node type and specified format. */
1806 gst_element = ms_element_create_from_ini(plug_info, type);
1809 /* 3. Third priority:
1810 * If previous cases did not create a valid gst_element,
1811 * try to find compatible plugin in gstreamer registry.
1812 * Elements that are compatible but defined as excluded will be skipped*/
1814 /* Read exclude elements list */
1815 gst_element = ms_element_create_by_registry(plug_info, type);
1818 if (type == MEDIA_STREAMER_NODE_TYPE_FILTER) {
1819 if (plug_info->src_caps)
1820 g_object_set(G_OBJECT(gst_element), "caps", plug_info->src_caps, NULL);
1828 GstElement *ms_rtp_element_create(void)
1830 GstElement *rtp_container = NULL;
1834 rtp_container = gst_bin_new("rtp_container");
1835 ms_retvm_if(!rtp_container, (GstElement *) NULL, "Error: creating elements for rtp container");
1837 ms_add_no_target_ghostpad(rtp_container, MS_PAD_VIDEO_OUT, GST_PAD_SRC);
1838 ms_add_no_target_ghostpad(rtp_container, MS_PAD_AUDIO_OUT, GST_PAD_SRC);
1839 ms_add_no_target_ghostpad(rtp_container, MS_PAD_VIDEO_IN, GST_PAD_SINK);
1840 ms_add_no_target_ghostpad(rtp_container, MS_PAD_AUDIO_IN, GST_PAD_SINK);
1842 ms_add_no_target_ghostpad(rtp_container, MS_PAD_VIDEO_IN"-rtp", GST_PAD_SINK);
1843 ms_add_no_target_ghostpad(rtp_container, MS_PAD_AUDIO_IN"-rtp", GST_PAD_SINK);
1845 /* Add RTP node parameters as GObject data with destroy function */
1846 MS_SET_INT_PARAM(rtp_container, MEDIA_STREAMER_PARAM_VIDEO_IN_PORT, RTP_STREAM_DISABLED);
1847 MS_SET_INT_PARAM(rtp_container, MEDIA_STREAMER_PARAM_AUDIO_IN_PORT, RTP_STREAM_DISABLED);
1848 MS_SET_INT_PARAM(rtp_container, MEDIA_STREAMER_PARAM_VIDEO_OUT_PORT, RTP_STREAM_DISABLED);
1849 MS_SET_INT_PARAM(rtp_container, MEDIA_STREAMER_PARAM_AUDIO_OUT_PORT, RTP_STREAM_DISABLED);
1850 MS_SET_INT_STATIC_STRING_PARAM(rtp_container, MEDIA_STREAMER_PARAM_HOST, "localhost");
1851 MS_SET_INT_CAPS_PARAM(rtp_container, MS_PARAM_VIDEO_IN_FORMAT, gst_caps_new_any());
1852 MS_SET_INT_CAPS_PARAM(rtp_container, MS_PARAM_AUDIO_IN_FORMAT, gst_caps_new_any());
1856 return rtp_container;
1860 static gboolean __ms_parse_gst_error(media_streamer_s *ms_streamer, GstMessage *message, GError *error)
1862 media_streamer_error_e ret_error = MEDIA_STREAMER_ERROR_NONE;
1866 ms_retvm_if(!ms_streamer, FALSE, "Error: invalid Media Streamer handle.");
1867 ms_retvm_if(!message, FALSE, "Error: invalid bus message handle.");
1868 ms_retvm_if(!error, FALSE, "Error: invalid error handle.");
1870 if (error->domain == GST_CORE_ERROR)
1871 ret_error = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
1872 else if (error->domain == GST_LIBRARY_ERROR)
1873 ret_error = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
1874 else if (error->domain == GST_RESOURCE_ERROR)
1875 ret_error = MEDIA_STREAMER_ERROR_RESOURCE_CONFLICT;
1876 else if (error->domain == GST_STREAM_ERROR)
1877 ret_error = MEDIA_STREAMER_ERROR_CONNECTION_FAILED;
1879 ret_error = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
1881 /* post error to application */
1882 if (ms_streamer->error_cb.callback) {
1883 media_streamer_error_cb error_cb = (media_streamer_error_cb) ms_streamer->error_cb.callback;
1884 error_cb((media_streamer_h) ms_streamer, ret_error, ms_streamer->error_cb.user_data);
1893 static GstPadProbeReturn __ms_element_event_probe(GstPad * pad, GstPadProbeInfo *info, gpointer user_data)
1895 GstElement *parent_element = NULL;
1896 GstEvent *event = NULL;
1898 parent_element = gst_pad_get_parent_element(pad);
1899 if (!parent_element) {
1900 ms_error("filed to get parent_elem");
1901 return GST_PAD_PROBE_PASS;
1904 event = GST_PAD_PROBE_INFO_EVENT(info);
1906 if (GST_PAD_PROBE_INFO_TYPE(info) & GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM) {
1907 if (GST_EVENT_TYPE(event) == GST_EVENT_BUFFERSIZE) {
1908 GValue *val_ = (GValue *) g_object_get_data(G_OBJECT(parent_element), "pad_sink");
1909 ms_info("Set locking probe [%d] on [%s] pad of [%s] element", g_value_get_int(val_), GST_PAD_NAME(pad), GST_ELEMENT_NAME(parent_element));
1910 MS_SAFE_UNREF(parent_element);
1911 return GST_PAD_PROBE_OK;
1915 MS_SAFE_UNREF(parent_element);
1917 return GST_PAD_PROBE_PASS;
1920 gboolean ms_element_lock_state(const GValue *item, GValue *ret, gpointer user_data)
1922 GstElement *sink_element = NULL;
1923 GstPad *sink_pad = NULL;
1928 sink_element = GST_ELEMENT(g_value_get_object(item));
1929 ms_retvm_if(!sink_element, FALSE, "Handle is NULL");
1931 g_value_set_boolean(ret, FALSE);
1933 sink_pad = gst_element_get_static_pad(sink_element, "sink");
1935 ms_info("Failed to get static pad of element [%s]", GST_ELEMENT_NAME(sink_element));
1938 if (!gst_pad_is_blocked(sink_pad)) {
1939 probe_id = gst_pad_add_probe(sink_pad, GST_PAD_PROBE_TYPE_BLOCK_DOWNSTREAM, __ms_element_event_probe, NULL, NULL);
1940 MS_SET_INT_PARAM(sink_element, "pad_sink", probe_id);
1941 ms_info("Added locking probe [%d] on pad [%s] of element [%s]", probe_id, GST_PAD_NAME(sink_pad), GST_ELEMENT_NAME(sink_element));
1943 ms_info("Pad [%s] of element [%s] is already locked", GST_PAD_NAME(sink_pad), GST_ELEMENT_NAME(sink_element));
1945 MS_SAFE_UNREF(sink_pad);
1947 g_value_set_boolean(ret, TRUE);
1954 gboolean ms_element_unlock_state(const GValue *item, GValue *ret, gpointer user_data)
1956 GstElement *sink_element = NULL;
1958 GstPad *sink_pad = NULL;
1962 g_value_set_boolean(ret, FALSE);
1963 sink_element = GST_ELEMENT(g_value_get_object(item));
1964 ms_retvm_if(!sink_element, FALSE, "Handle is NULL");
1966 val = (GValue *) g_object_get_data(G_OBJECT(sink_element), "pad_sink");
1968 sink_pad = gst_element_get_static_pad(sink_element, "sink");
1970 ms_info("Failed to get static pad of element [%s]", GST_ELEMENT_NAME(sink_element));
1973 if (gst_pad_is_blocked(sink_pad)) {
1974 ms_info("Removing locking probe [%d] ID on [%s] pad of [%s] element", g_value_get_int(val), GST_PAD_NAME(sink_pad), GST_ELEMENT_NAME(sink_element));
1975 gst_pad_remove_probe(sink_pad, g_value_get_int(val));
1977 ms_info("No locking Probe on pad [%s] of element [%s]", GST_PAD_NAME(sink_pad), GST_ELEMENT_NAME(sink_element));
1979 MS_SAFE_UNREF(sink_pad);
1982 g_value_set_boolean(ret, TRUE);
1989 static gboolean __ms_skip_set_state(media_streamer_s *ms_streamer)
1991 media_streamer_node_s *webrtc = NULL;
1993 ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer is NULL");
1994 ms_retvm_if(ms_streamer->nodes_table == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "nodes_table is NULL");
1998 webrtc = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "webrtc_container");
1999 if (webrtc && ms_streamer->pend_state == MEDIA_STREAMER_STATE_READY) {
2007 static gboolean __ms_bus_cb(GstBus *bus, GstMessage *message, gpointer userdata)
2009 int ret = MEDIA_STREAMER_ERROR_NONE;
2010 media_streamer_s *ms_streamer = NULL;
2012 gchar *debug = NULL;
2013 gchar *state_transition_name = NULL;
2014 GstState gst_state_old = GST_STATE_VOID_PENDING;
2015 GstState gst_state_new = GST_STATE_VOID_PENDING;
2016 GstState gst_state_pending = GST_STATE_VOID_PENDING;
2018 ms_streamer = (media_streamer_s *) userdata;
2019 ms_retvm_if(ms_streamer == NULL, FALSE, "Handle is NULL");
2020 ms_retvm_if(ms_streamer->pipeline == NULL, FALSE, "Pipeline doesn`t exist");
2023 if (message == NULL) {
2024 ms_debug("message is null");
2028 switch (GST_MESSAGE_TYPE(message)) {
2029 case GST_MESSAGE_ERROR:
2030 gst_message_parse_error(message, &err, &debug);
2032 /* Transform gst error code to media streamer error code.
2033 * then post it to application if needed */
2034 __ms_parse_gst_error(ms_streamer, message, err);
2036 ms_error("Error from [%s]: %s", GST_OBJECT_NAME(GST_OBJECT_CAST(GST_ELEMENT(GST_MESSAGE_SRC(message)))), err->message);
2039 MS_SAFE_GFREE(debug);
2042 case GST_MESSAGE_STATE_CHANGED:
2043 if (GST_MESSAGE_SRC(message) != GST_OBJECT(ms_streamer->pipeline))
2046 gst_message_parse_state_changed(message, &gst_state_old, &gst_state_new, &gst_state_pending);
2047 state_transition_name = g_strdup_printf("Old[GST_STATE_%s] New[GST_STATE_%s] Pending[GST_STATE_%s]",
2048 gst_element_state_get_name(gst_state_old), gst_element_state_get_name(gst_state_new),
2049 gst_element_state_get_name(gst_state_pending));
2050 ms_info("GST_MESSAGE_STATE_CHANGED: %s", state_transition_name);
2051 ms_generate_dots(ms_streamer->pipeline, state_transition_name);
2052 MS_SAFE_GFREE(state_transition_name);
2054 if (gst_state_new < GST_STATE_PAUSED)
2057 if (ms_streamer->pend_state == ms_streamer->state) {
2058 ms_info("pend_state(%d) is same with current state(%d), skip triggering callback.",
2059 ms_streamer->pend_state, ms_streamer->state);
2063 if(__ms_skip_set_state(ms_streamer)) {
2064 ms_info("Skip set state, state is set after connecting ICE connection.");
2068 ms_update_state_from_pend_state(ms_streamer);
2071 case GST_MESSAGE_ASYNC_DONE:
2072 ms_debug("GST_MESSAGE_ASYNC_DONE");
2074 if (GST_MESSAGE_SRC(message) != GST_OBJECT(ms_streamer->pipeline))
2077 if (ms_streamer->is_seeking) {
2079 g_mutex_lock(&ms_streamer->mutex_lock);
2080 ms_streamer->pend_state = MEDIA_STREAMER_STATE_SEEKING;
2081 g_mutex_unlock(&ms_streamer->mutex_lock);
2083 if (ms_streamer->seek_done_cb.callback) {
2084 media_streamer_position_changed_cb cb = (media_streamer_position_changed_cb) ms_streamer->seek_done_cb.callback;
2085 cb(ms_streamer->seek_done_cb.user_data);
2088 g_mutex_lock(&ms_streamer->mutex_lock);
2089 ms_streamer->is_seeking = FALSE;
2090 ms_streamer->pend_state = MEDIA_STREAMER_STATE_PLAYING;
2091 ms_streamer->seek_done_cb.callback = NULL;
2092 ms_streamer->seek_done_cb.user_data = NULL;
2093 g_mutex_unlock(&ms_streamer->mutex_lock);
2097 case GST_MESSAGE_EOS:
2098 ms_info("GST_MESSAGE_EOS end-of-stream");
2099 ret = ms_element_set_state(ms_streamer->pipeline, GST_STATE_PAUSED);
2100 ms_retvm_if(ret != MEDIA_STREAMER_ERROR_NONE, FALSE, "Failed to pause pipeline");
2110 static int __ms_gstreamer_init(media_streamer_s *ms_streamer)
2112 int ret = MEDIA_STREAMER_ERROR_NONE;
2116 gboolean gst_ret = 0;
2121 ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
2123 argc = (int *)malloc(sizeof(int));
2125 ms_error("Error allocation memory");
2126 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2129 /* get argc(number of command line option), argc is always one without option */
2131 if (ms_streamer->ini.gst_args)
2132 (*argc) += g_strv_length(ms_streamer->ini.gst_args); /* default is "--gst-debug = 2 */
2134 argv = (char **)calloc(*argc, sizeof(char*));
2137 ms_error("Error allocation memory");
2138 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2141 argv[0] = g_strdup("MediaStreamer");
2143 if (ms_streamer->ini.gst_args) {
2144 for ( ; ms_streamer->ini.gst_args[i]; ++i) {
2146 ms_error("need to check, prevent overrun");
2149 argv[i+1] = ms_streamer->ini.gst_args[i];
2150 ms_debug("Add [%s] gstreamer parameter.", argv[i+1]);
2154 gst_ret = gst_init_check(argc, &argv, &err);
2156 /* Clean memory of gstreamer arguments*/
2157 g_strfreev(ms_streamer->ini.gst_args);
2158 ms_streamer->ini.gst_args = NULL;
2160 for (i = 1; i < *argc; i++)
2163 MS_SAFE_FREE(argv[0]);
2168 ms_error("Error: Failed to initialize GStreamer [%s].", err->message);
2169 g_clear_error(&err);
2170 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2178 int ms_pipeline_create(media_streamer_s *ms_streamer)
2180 int ret = MEDIA_STREAMER_ERROR_NONE;
2184 ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer is NULL");
2186 /* initialize gstreamer with configured parameter */
2187 ret = __ms_gstreamer_init(ms_streamer);
2188 if (ret != MEDIA_STREAMER_ERROR_NONE)
2191 ms_streamer->pipeline = gst_pipeline_new(MEDIA_STREAMER_PIPELINE_NAME);
2192 ms_retvm_if(ms_streamer->pipeline == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating pipeline");
2194 ms_streamer->bus = gst_pipeline_get_bus(GST_PIPELINE(ms_streamer->pipeline));
2195 ms_retvm_if(ms_streamer->bus == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error getting the bus of the pipeline");
2197 ms_streamer->bus_watcher = gst_bus_add_watch(ms_streamer->bus, (GstBusFunc) __ms_bus_cb, ms_streamer);
2199 ms_streamer->src_bin = gst_bin_new(MEDIA_STREAMER_SRC_BIN_NAME);
2200 ms_retvm_if(ms_streamer->src_bin == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating Src bin");
2202 ms_streamer->sink_bin = gst_bin_new(MEDIA_STREAMER_SINK_BIN_NAME);
2203 ms_retvm_if(ms_streamer->sink_bin == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating Sink bin");
2205 ms_streamer->transform_bin = gst_bin_new(MEDIA_STREAMER_TRANSFORM_BIN_NAME);
2206 ms_retvm_if(ms_streamer->transform_bin == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Error creating Transform bin");
2208 gst_bin_add_many(GST_BIN(ms_streamer->pipeline), ms_streamer->src_bin, ms_streamer->sink_bin, ms_streamer->transform_bin, NULL);
2209 ms_info("Media streamer pipeline created successfully.");
2216 static gboolean __find_node(gpointer key, gpointer value, gpointer user_data)
2218 gchar *node_name = (gchar *)user_data;
2220 return g_strrstr((char *)key, node_name) != NULL;
2223 static void __ms_pending_pads_remove(void *data)
2229 ms_retm_if(data == NULL, "data is NULL");
2231 pad = GST_PAD(data);
2237 static gboolean __ms_bin_unprepare(media_streamer_s *ms_streamer, GstElement *bin)
2239 GValue element = G_VALUE_INIT;
2240 GstIterator *bin_iterator = NULL;
2241 gboolean ret = TRUE; /* If the bin doesn't have any elements, it returns TRUE */
2242 GstElement *found_element = NULL;
2243 GstIteratorResult it_res = GST_ITERATOR_ERROR;
2244 media_streamer_node_s *found_node = NULL;
2248 ms_retvm_if(ms_streamer == NULL, FALSE, "ms_streamer is NULL");
2249 ms_retvm_if(bin == NULL, FALSE, "bin is NULL");
2250 ms_retvm_if(ms_streamer->nodes_table == NULL, FALSE, "ms_streamer->nodes_table is NULL");
2252 bin_iterator = gst_bin_iterate_elements(GST_BIN(bin));
2253 it_res = gst_iterator_next(bin_iterator, &element);
2255 while (GST_ITERATOR_OK == it_res) {
2256 found_element = (GstElement *) g_value_get_object(&element);
2258 /* Get node of this element if it appears as node */
2259 found_node = (media_streamer_node_s *) g_hash_table_lookup(ms_streamer->nodes_table, GST_ELEMENT_NAME(found_element));
2261 if (!found_node->linked_by_user)
2262 ret = ret && ms_element_unlink(found_element);
2264 ms_info("Unprepare skipped user-linked node [%s]", found_node->name);
2265 ms_generate_dots(ms_streamer->pipeline, GST_ELEMENT_NAME(found_element));
2267 ret = ret && ms_bin_remove_element(found_element);
2270 g_value_reset(&element);
2272 it_res = gst_iterator_next(bin_iterator, &element);
2273 if (GST_ITERATOR_RESYNC == it_res) {
2274 gst_iterator_resync(bin_iterator);
2275 it_res = gst_iterator_next(bin_iterator, &element);
2279 g_value_unset(&element);
2280 gst_iterator_free(bin_iterator);
2287 int ms_pipeline_prepare(media_streamer_s *ms_streamer)
2289 int ret = MEDIA_STREAMER_ERROR_NONE;
2290 media_streamer_node_s *rtp = NULL;
2291 media_streamer_node_s *webrtc = NULL;
2292 media_streamer_node_s *demux = NULL;
2293 media_streamer_node_s *adaptive_src = NULL;
2294 media_streamer_node_s *adaptive_sink = NULL;
2295 gchar *find_node_name = "demux";
2299 ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer is NULL");
2300 ms_retvm_if(ms_streamer->nodes_table == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer->nodes_table is NULL");
2301 ms_retvm_if(ms_streamer->src_bin == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer->src_bin is NULL");
2302 ms_retvm_if(ms_streamer->transform_bin == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer->transform_bin is NULL");
2304 rtp = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "rtp_container");
2305 webrtc = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "webrtc_container");
2306 demux = (media_streamer_node_s *)g_hash_table_find(ms_streamer->nodes_table, (GHRFunc)__find_node, find_node_name);
2307 adaptive_src = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "adaptive_src");
2308 adaptive_sink = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "adaptive_sink");
2311 ret = ms_rtp_node_prepare(rtp);
2312 } else if (webrtc) {
2313 ret = ms_webrtc_node_prepare(ms_streamer, webrtc);
2315 ret = ms_demux_node_prepare(ms_streamer, demux);
2316 if (MEDIA_STREAMER_ERROR_NONE != ret)
2317 ms_error("Failed to prepare demux element");
2319 GstBin *nodes_bin = GST_BIN(ms_streamer->src_bin);
2320 if (nodes_bin->numchildren == 0) {
2321 ms_debug(" No any node is added to [%s]", GST_ELEMENT_NAME(ms_streamer->src_bin));
2322 return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
2324 nodes_bin = GST_BIN(ms_streamer->sink_bin);
2325 if (nodes_bin->numchildren == 0) {
2326 ms_debug(" No any node is added to [%s]", GST_ELEMENT_NAME(ms_streamer->sink_bin));
2327 return MEDIA_STREAMER_ERROR_INVALID_PARAMETER;
2332 if (GST_BIN(ms_streamer->transform_bin)->numchildren == 0)
2333 ret = ms_adaptive_src_node_prepare(adaptive_src, true);
2335 ret = ms_adaptive_src_node_prepare(adaptive_src, false);
2339 ret = ms_adaptive_sink_node_prepare(ms_streamer, adaptive_sink);
2341 if (ret != MEDIA_STREAMER_ERROR_NONE)
2344 ret = ms_bin_foreach_elements(GST_BIN(ms_streamer->sink_bin), ms_sink_node_prepare_iter, ms_streamer);
2345 if (MEDIA_STREAMER_ERROR_NONE != ret) {
2346 ms_error("Failed to prepare nodes within sink bin");
2350 ret = ms_bin_foreach_elements(GST_BIN(ms_streamer->src_bin), ms_src_node_prepare_iter, ms_streamer);
2351 if (MEDIA_STREAMER_ERROR_NONE != ret) {
2352 ms_error("Failed to prepare nodes within src bin");
2356 ret = ms_set_state(ms_streamer, MEDIA_STREAMER_STATE_READY);
2357 if (ret != MEDIA_STREAMER_ERROR_NONE)
2365 ms_pipeline_unprepare(ms_streamer);
2369 int ms_pipeline_unprepare(media_streamer_s *ms_streamer)
2371 int ret = MEDIA_STREAMER_ERROR_NONE;
2375 ms_retvm_if(ms_streamer == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
2376 ms_retvm_if(ms_streamer->nodes_table == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer->nodes_table is NULL");
2378 ret = ms_set_state(ms_streamer, MEDIA_STREAMER_STATE_IDLE);
2379 if (ret != MEDIA_STREAMER_ERROR_NONE)
2380 ms_error("Failed to unprepare pipeline");
2382 if (!ms_streamer->is_interrupted) {
2383 /* FIXME: it seems possible to move codes below to ms_set_state(), need to check the history. */
2384 /* Unprepare resources in case of failure */
2385 if (ms_streamer->video_decoder_resource != NULL) {
2386 ret = mm_resource_manager_mark_for_release(ms_streamer->resource_manager,
2387 ms_streamer->video_decoder_resource);
2388 if (ret != MM_RESOURCE_MANAGER_ERROR_NONE)
2389 ms_error("Failed to mark resources for release");
2391 ret = mm_resource_manager_commit(ms_streamer->resource_manager);
2392 if (ret != MEDIA_STREAMER_ERROR_NONE)
2393 ms_error("Failed to release resources");
2395 ms_streamer->video_decoder_resource = NULL;
2399 /* Disconnects and clean all autoplug signals */
2400 g_list_free_full(ms_streamer->autoplug_sig_list, ms_signal_destroy);
2401 ms_streamer->autoplug_sig_list = NULL;
2403 /* Removes all pending pads according to list */
2404 g_list_free_full(ms_streamer->pads_types_list, __ms_pending_pads_remove);
2405 ms_streamer->pads_types_list = NULL;
2407 media_streamer_node_s *rtp_node = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "rtp_container");
2409 g_list_free_full(rtp_node->sig_list, ms_signal_destroy);
2410 rtp_node->sig_list = NULL;
2411 __ms_bin_unprepare(ms_streamer, rtp_node->gst_element);
2414 __ms_bin_unprepare(ms_streamer, ms_streamer->src_bin);
2415 __ms_bin_unprepare(ms_streamer, ms_streamer->transform_bin);
2416 __ms_bin_unprepare(ms_streamer, ms_streamer->sink_bin);
2423 static const char *g_gst_element_get_state_ret_str_arr[] = {
2424 "GST_STATE_CHANGE_FAILURE",
2425 "GST_STATE_CHANGE_SUCCESS",
2426 "GST_STATE_CHANGE_ASYNC",
2427 "GST_STATE_CHANGE_NO_PREROLL"
2430 void ms_pipeline_get_state(media_streamer_s *ms_streamer)
2432 GstState state_old = GST_STATE_NULL, state_new = GST_STATE_NULL;
2433 GstStateChangeReturn ret_state = -1;
2435 ms_retm_if(ms_streamer == NULL, "ms_streamer is NULL");
2436 ms_retm_if(ms_streamer->pipeline == NULL, "ms_streamer->pipeline is NULL");
2438 ret_state = gst_element_get_state(ms_streamer->pipeline, &state_old, &state_new, GST_CLOCK_TIME_NONE);
2439 if (ret_state == GST_STATE_CHANGE_FAILURE)
2440 ms_error("Failed to gst_element_get_state()");
2442 ms_info("[%s] Got state: old [%s], new [%s]", g_gst_element_get_state_ret_str_arr[ret_state],
2443 gst_element_state_get_name(state_old), gst_element_state_get_name(state_new));
2446 gboolean ms_pipeline_is_get_state_with_no_preroll(media_streamer_s *ms_streamer)
2448 GstState state_old = GST_STATE_NULL, state_new = GST_STATE_NULL;
2449 GstStateChangeReturn ret_state = -1;
2451 ms_retvm_if(ms_streamer == NULL, FALSE, "ms_streamer is NULL");
2452 ms_retvm_if(ms_streamer->pipeline == NULL, FALSE, "ms_streamer->pipeline is NULL");
2454 ret_state = gst_element_get_state(ms_streamer->pipeline, &state_old, &state_new, GST_CLOCK_TIME_NONE);
2455 if (ret_state == GST_STATE_CHANGE_NO_PREROLL) {
2456 ms_info("[%s] Got state: old [%s], new [%s]", g_gst_element_get_state_ret_str_arr[ret_state],
2457 gst_element_state_get_name(state_old), gst_element_state_get_name(state_new));
2464 GstCaps *ms_create_caps_from_fmt(media_format_h fmt)
2466 GstCaps *caps = NULL;
2467 gchar *caps_name = NULL;
2468 media_format_mimetype_e mime;
2469 int width, height, avg_bps, max_bps, channel, samplerate, bit;
2473 if (!media_format_get_audio_info(fmt, &mime, &channel, &samplerate, &bit, &avg_bps)) {
2474 if (MEDIA_FORMAT_RAW == (mime & MEDIA_FORMAT_RAW)) {
2475 caps = gst_caps_new_simple("audio/x-raw", "format", G_TYPE_STRING, ms_convert_audio_mime_to_string_format(mime), NULL);
2476 } else if (MEDIA_FORMAT_ENCODED == (mime & MEDIA_FORMAT_ENCODED)) {
2477 if (mime == MEDIA_FORMAT_AAC)
2478 caps = gst_caps_new_simple(ms_convert_audio_mime_to_string_format(mime), "mpegversion", G_TYPE_INT, 4, NULL);
2479 else if (mime == MEDIA_FORMAT_MP3)
2480 caps = gst_caps_new_simple(ms_convert_audio_mime_to_string_format(mime), "mpegversion", G_TYPE_INT, 1, NULL);
2482 caps = gst_caps_new_simple(ms_convert_audio_mime_to_string_format(mime), "channels", G_TYPE_INT, channel, "rate", G_TYPE_INT, samplerate, NULL);
2484 caps_name = gst_caps_to_string(caps);
2485 ms_info("Creating Audio Caps from media format [%s]", caps_name);
2487 } else if (!media_format_get_video_info(fmt, &mime, &width, &height, &avg_bps, &max_bps)) {
2488 if (MEDIA_FORMAT_RAW == (mime & MEDIA_FORMAT_RAW))
2489 caps = gst_caps_new_simple("video/x-raw", "framerate", GST_TYPE_FRACTION, max_bps,
2490 avg_bps, "format", G_TYPE_STRING, ms_convert_video_mime_to_string_format(mime), "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
2491 else if (MEDIA_FORMAT_ENCODED == (mime & MEDIA_FORMAT_ENCODED))
2492 caps = gst_caps_new_simple(ms_convert_video_mime_to_string_format(mime), "framerate", GST_TYPE_FRACTION, max_bps,
2493 avg_bps, "width", G_TYPE_INT, width, "height", G_TYPE_INT, height, NULL);
2494 caps_name = gst_caps_to_string(caps);
2495 ms_info("Creating Video Caps from media format [%s]", caps_name);
2497 } else if (!media_format_get_container_mime(fmt, &mime)) {
2498 caps = gst_caps_new_empty_simple(ms_convert_container_mime_to_string_format(mime));
2499 caps_name = gst_caps_to_string(caps);
2500 ms_info("Creating Container Caps from media format [%s]", caps_name);
2503 ms_error("Error getting media format information");
2505 MS_SAFE_GFREE(caps_name);
2512 static media_format_h __ms_create_fmt_from_caps(GstCaps *caps)
2515 GstStructure *pad_struct;
2516 int fmt_ret = MEDIA_FORMAT_ERROR_NONE;
2517 const gchar *pad_type = NULL;
2518 const gchar *pad_format = NULL;
2519 int channels = 0, bps = 0;
2520 int width = 0, height = 0, avg_bps = 0, max_bps = 0;
2524 ms_retvm_if(caps == NULL, NULL, "Error: empty caps!");
2526 if (gst_caps_is_any(caps)) {
2527 ms_debug("Can not get format info from any caps!");
2531 fmt_ret = media_format_create(&fmt);
2532 ms_retvm_if(fmt_ret != MEDIA_FORMAT_ERROR_NONE, NULL, "Error: while creating media format object, err[%d]!", fmt_ret);
2534 pad_struct = gst_caps_get_structure(caps, 0);
2535 pad_type = gst_structure_get_name(pad_struct);
2536 pad_format = pad_type;
2538 /* Got raw format type if needed */
2539 if (g_strrstr(pad_type, "/x-raw"))
2540 pad_format = gst_structure_get_string(pad_struct, "format");
2542 ms_debug("Pad type is [%s], format: [%s]", pad_type, pad_format);
2544 if (MS_ELEMENT_IS_VIDEO(pad_type)) {
2545 gst_structure_get_int(pad_struct, "width", &width);
2546 gst_structure_get_fraction(pad_struct, "framerate", &max_bps, &avg_bps);
2547 gst_structure_get_int(pad_struct, "height", &height);
2549 media_format_set_video_mime(fmt, ms_convert_video_string_format_to_media_format(pad_format));
2550 media_format_set_video_width(fmt, width);
2551 media_format_set_video_height(fmt, height);
2552 media_format_set_video_avg_bps(fmt, avg_bps);
2553 media_format_set_video_max_bps(fmt, max_bps);
2554 } else if (MS_ELEMENT_IS_AUDIO(pad_type)) {
2555 media_format_set_audio_mime(fmt, ms_convert_audio_string_format_to_media_format(pad_format));
2556 gst_structure_get_int(pad_struct, "channels", &channels);
2557 media_format_set_audio_channel(fmt, channels);
2558 gst_structure_get_int(pad_struct, "rate", &bps);
2559 media_format_set_audio_avg_bps(fmt, bps);
2567 int ms_element_pad_names(GstElement *gst_element, GstPadDirection pad_type, char ***pad_name_array, int *pads_count)
2569 int ret = MEDIA_STREAMER_ERROR_NONE;
2571 GValue elem = G_VALUE_INIT;
2573 char **pad_names = NULL;
2574 GstIterator *pad_iterator = NULL;
2575 gchar *pad_name = NULL;
2579 ms_retvm_if(gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "gst_element is NULL");
2580 ms_retvm_if(pad_name_array == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "pad_name_array is NULL");
2581 ms_retvm_if(pads_count == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "pads_count is NULL");
2583 if (pad_type == GST_PAD_SRC) {
2584 pad_iterator = gst_element_iterate_src_pads(gst_element);
2585 } else if (pad_type == GST_PAD_SINK) {
2586 pad_iterator = gst_element_iterate_sink_pads(gst_element);
2588 pad_iterator = gst_element_iterate_pads(gst_element);
2589 ms_info("Iterating all pads of the Gst element");
2592 while (GST_ITERATOR_OK == gst_iterator_next(pad_iterator, &elem)) {
2593 pad = (GstPad *) g_value_get_object(&elem);
2595 pad_names = (char **)realloc(pad_names, sizeof(char *) * (pad_number + 1));
2597 ms_error("Error allocation memory");
2598 ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2600 MS_SAFE_FREE(pad_names);
2604 pad_name = gst_pad_get_name(pad);
2605 pad_names[pad_number++] = strdup(pad_name);
2608 g_value_reset(&elem);
2611 g_value_unset(&elem);
2612 gst_iterator_free(pad_iterator);
2614 *pad_name_array = pad_names;
2615 *pads_count = pad_number;
2622 int ms_element_get_pad_fmt(GstElement *gst_element, const char *pad_name, media_format_h *fmt)
2624 int ret = MEDIA_STREAMER_ERROR_NONE;
2625 GstCaps *allowed_caps = NULL;
2626 GstCaps *format_caps = NULL;
2628 GValue *value = NULL;
2632 ms_retvm_if(gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "gst_element is NULL");
2633 ms_retvm_if(pad_name == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "pad_name is NULL");
2634 ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "fmt is NULL");
2637 pad = gst_element_get_static_pad(gst_element, pad_name);
2638 ms_retvm_if(pad == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Fail to get pad [%s] from element [%s].", pad_name, GST_ELEMENT_NAME(gst_element));
2640 value = (GValue *) g_object_get_data(G_OBJECT(gst_element), pad_name);
2642 format_caps = GST_CAPS(gst_value_get_caps(value));
2644 ms_info(" No any format is set for pad [%s]", pad_name);
2646 allowed_caps = gst_pad_get_allowed_caps(pad);
2648 if (gst_caps_is_empty(allowed_caps) || gst_caps_is_any(allowed_caps)) {
2650 *fmt = __ms_create_fmt_from_caps(format_caps);
2652 ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2654 *fmt = __ms_create_fmt_from_caps(allowed_caps);
2658 *fmt = __ms_create_fmt_from_caps(format_caps);
2660 ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2664 gst_caps_unref(allowed_caps);
2673 int ms_element_set_fmt(GstElement *element, const char *pad_name, media_format_h fmt)
2675 gboolean can_accept = FALSE;
2676 GstCaps *fmt_caps = NULL;
2677 GstElementFactory *factory = NULL;
2678 GstPad *node_pad = NULL;
2682 ms_retvm_if(!element || !pad_name || !fmt, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
2684 fmt_caps = ms_create_caps_from_fmt(fmt);
2685 ms_retvm_if(!fmt_caps, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Can't convert fmt into Caps");
2687 factory = gst_element_get_factory(element);
2688 node_pad = gst_element_get_static_pad(element, pad_name);
2690 if (node_pad && GST_PAD_IS_SRC(node_pad))
2691 can_accept = gst_element_factory_can_src_any_caps(factory, fmt_caps);
2692 else if (node_pad && GST_PAD_IS_SINK(node_pad))
2693 can_accept = gst_element_factory_can_sink_any_caps(factory, fmt_caps);
2695 ms_error("[%s] doesn`t have valid pad [%s]", GST_ELEMENT_NAME(element), pad_name);
2699 gst_caps_unref(fmt_caps);
2700 ms_error("[%s]'s pad [%s] can`t be set with the given format", GST_ELEMENT_NAME(element), pad_name);
2701 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2703 MS_SET_INT_CAPS_PARAM(element, pad_name, fmt_caps);
2704 ms_info("[%s]'s pad [%s] was set with given format", GST_ELEMENT_NAME(element), pad_name);
2707 MS_SAFE_UNREF(node_pad);
2711 return MEDIA_STREAMER_ERROR_NONE;
2714 gboolean ms_gst_seek(GstElement *element, gint64 g_time, GstSeekFlags seek_flag)
2716 gboolean result = FALSE;
2717 GstEvent *event = NULL;
2721 ms_retvm_if(element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Element is NULL");
2723 event = gst_event_new_seek(1.0, GST_FORMAT_TIME, seek_flag,
2724 GST_SEEK_TYPE_SET, g_time,
2725 GST_SEEK_TYPE_NONE, GST_CLOCK_TIME_NONE);
2727 result = gst_element_send_event(element, event);
2734 int ms_element_push_packet(GstElement *src_element, media_packet_h packet)
2736 GstBuffer *buffer = NULL;
2737 GstFlowReturn gst_ret = GST_FLOW_OK;
2738 guchar *buffer_data = NULL;
2742 ms_retvm_if(src_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
2744 if (packet == NULL) {
2745 g_signal_emit_by_name(G_OBJECT(src_element), "end-of-stream", &gst_ret, NULL);
2746 return MEDIA_STREAMER_ERROR_NONE;
2749 media_packet_get_buffer_data_ptr(packet, (void **)&buffer_data);
2751 if (buffer_data != NULL) {
2752 GstMapInfo buff_info = GST_MAP_INFO_INIT;
2754 guint64 duration = 0;
2757 media_packet_get_buffer_size(packet, &size);
2759 buffer = gst_buffer_new_and_alloc(size);
2761 ms_error("Failed to allocate memory for push buffer");
2762 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2765 if (gst_buffer_map(buffer, &buff_info, GST_MAP_READWRITE)) {
2766 memcpy(buff_info.data, buffer_data, size);
2767 buff_info.size = size;
2768 gst_buffer_unmap(buffer, &buff_info);
2771 media_packet_get_pts(packet, &pts);
2772 GST_BUFFER_PTS(buffer) = pts;
2774 media_packet_get_duration(packet, &duration);
2775 GST_BUFFER_DURATION(buffer) = duration;
2777 g_signal_emit_by_name(G_OBJECT(src_element), "push-buffer", buffer, &gst_ret, NULL);
2778 gst_buffer_unref(buffer);
2781 g_signal_emit_by_name(G_OBJECT(src_element), "end-of-stream", &gst_ret, NULL);
2784 if (gst_ret != GST_FLOW_OK)
2785 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2789 return MEDIA_STREAMER_ERROR_NONE;
2792 int ms_element_pull_packet(GstElement *sink_element, media_packet_h *packet)
2794 int ret = MEDIA_STREAMER_ERROR_NONE;
2795 GstSample *sample = NULL;
2796 media_format_h fmt = NULL;
2797 guint8 *buffer_res = NULL;
2798 GstMapInfo map = {0,};
2799 GstBuffer *buffer = NULL;
2803 ms_retvm_if(sink_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
2804 ms_retvm_if(packet == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "Handle is NULL");
2806 /* Retrieve the buffer */
2807 g_signal_emit_by_name(sink_element, "pull-sample", &sample, NULL);
2808 ms_retvm_if(sample == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION, "Pull sample failed!");
2810 ret = ms_element_get_pad_fmt(sink_element, "sink", &fmt);
2811 if (ret == MEDIA_STREAMER_ERROR_NONE) {
2812 buffer = gst_sample_get_buffer(sample);
2814 ms_error("Failed to get buffer from sample");
2815 media_format_unref(fmt);
2816 gst_sample_unref(sample);
2817 return MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2819 gst_buffer_map(buffer, &map, GST_MAP_READ);
2821 buffer_res = (guint8 *) malloc(map.size * sizeof(guint8));
2822 if (buffer_res != NULL) {
2823 memcpy(buffer_res, map.data, map.size);
2825 media_packet_create_from_external_memory(fmt, (void *)buffer_res, map.size, NULL, NULL, packet);
2826 media_packet_set_pts(*packet, GST_BUFFER_PTS(buffer));
2827 media_packet_set_dts(*packet, GST_BUFFER_DTS(buffer));
2828 media_packet_set_pts(*packet, GST_BUFFER_DURATION(buffer));
2830 ms_error("Error allocation memory for packet data");
2831 ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION;
2833 gst_buffer_unmap(buffer, &map);
2836 media_format_unref(fmt);
2837 gst_sample_unref(sample);
2844 static void __ms_typefound_cb(GstElement *typefind, guint probability, GstCaps *caps, gpointer data)
2846 media_streamer_s *ms_streamer = (media_streamer_s *) data;
2847 GstElement *decodebin = NULL;
2848 media_streamer_node_s *adaptive_sink = NULL;
2850 GstPad *src_pad = NULL;
2854 ms_retm_if(!typefind, "typefind is NULL");
2855 ms_retm_if(!ms_streamer, "data is NULL");
2857 adaptive_sink = (media_streamer_node_s *)g_hash_table_lookup(ms_streamer->nodes_table, "adaptive_sink");
2858 src_pad = gst_element_get_static_pad(typefind, "src");
2860 type = gst_caps_to_string(caps);
2861 if (g_strrstr(type, "video/mpegts") && adaptive_sink) {
2862 __ms_link_two_elements(typefind, src_pad, adaptive_sink->gst_element);
2864 decodebin = __ms_decodebin_create(ms_streamer, NULL);
2865 __ms_link_two_elements(typefind, src_pad, decodebin);
2868 MS_SAFE_UNREF(src_pad);
2874 int ms_find_type(media_streamer_s *ms_streamer, GstElement *src_element)
2876 GstElement *typefind = NULL;
2877 GstPad *src_pad = NULL;
2881 ms_retvm_if(!ms_streamer, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "ms_streamer is NULL");
2882 ms_retvm_if(!src_element, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "src_element is NULL");
2884 src_pad = gst_element_get_static_pad(src_element, "src");
2885 ms_retvm_if(src_pad == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION,
2886 "Error getting static_pad [src_pad]");
2888 typefind = gst_element_factory_make("typefind", "typefinder");
2889 ms_retvm_if(typefind == NULL, MEDIA_STREAMER_ERROR_INVALID_OPERATION,
2890 "Error creating element [typefind]");
2892 ms_bin_add_element(ms_streamer->transform_bin, typefind, TRUE);
2894 gst_element_sync_state_with_parent(typefind);
2896 g_signal_connect(typefind, "have-type", G_CALLBACK(__ms_typefound_cb), ms_streamer);
2898 __ms_link_two_elements(src_element, src_pad, typefind);
2900 MS_SAFE_UNREF(src_pad);
2904 return MEDIA_STREAMER_ERROR_NONE;