From 80a4023240b166d7f32779fdfddc6c10b0be1021 Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Tue, 8 Jun 2021 17:32:49 +0900 Subject: [PATCH] webrtc_source: Use GList to carry elements via parameter [Version] 0.2.8 [Issue Type] Refactoring Change-Id: Id19b2b6052799491b4c7558ea18170e203d94746 Signed-off-by: Sangchul Lee --- include/webrtc_private.h | 7 +- packaging/capi-media-webrtc.spec | 2 +- src/webrtc_private.c | 1 + src/webrtc_source.c | 461 ++++++++++++++++++++----------- 4 files changed, 302 insertions(+), 169 deletions(-) diff --git a/include/webrtc_private.h b/include/webrtc_private.h index d05da8ee..db07de52 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -158,9 +158,10 @@ do { \ return WEBRTC_ERROR_NOT_SUPPORTED; \ } while (0) -#define SAFE_FREE(src) { if (src) { free(src); src = NULL; } } -#define SAFE_GST_OBJECT_UNREF(src) { if (src) { gst_object_unref(src); src = NULL; } } -#define SAFE_STR(str) (str) ? str : "null" +#define SAFE_FREE(src) { if (src) { free(src); src = NULL; } } +#define SAFE_GST_OBJECT_UNREF(src) { if (src) { gst_object_unref(src); src = NULL; } } +#define SAFE_G_LIST_FREE(src) { if (src) { g_list_free(src); src = NULL; } } +#define SAFE_STR(str) (str) ? str : "null" #define PRINT_CAPS(x_caps, x_prefix) \ do { \ diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 96923de6..770ca9be 100644 --- a/packaging/capi-media-webrtc.spec +++ b/packaging/capi-media-webrtc.spec @@ -1,6 +1,6 @@ Name: capi-media-webrtc Summary: A WebRTC library in Tizen Native API -Version: 0.2.7 +Version: 0.2.8 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc_private.c b/src/webrtc_private.c index 16e4300b..9f86acc6 100644 --- a/src/webrtc_private.c +++ b/src/webrtc_private.c @@ -690,6 +690,7 @@ static void __webrtcbin_on_negotiation_needed_cb(GstElement *webrtcbin, gpointer webrtc->state = webrtc->pend_state; g_mutex_unlock(&webrtc->mutex); + _invoke_state_changed_cb(webrtc, old_state, webrtc->state); webrtc->negotiation_needed_cb_invoked = true; diff --git a/src/webrtc_source.c b/src/webrtc_source.c index c051d01f..2ad282aa 100644 --- a/src/webrtc_source.c +++ b/src/webrtc_source.c @@ -29,23 +29,41 @@ #define GST_KLASS_NAME_CONVERTER_AUDIO "Filter/Converter/Audio" #define GST_KLASS_NAME_CONVERTER_VIDEO "Filter/Converter/Video" -#define DEFAULT_ELEMENT_CAMERASRC "v4l2src" -#define DEFAULT_ELEMENT_AUDIOSRC "pulsesrc" -#define DEFAULT_ELEMENT_VIDEOTESTSRC "videotestsrc" -#define DEFAULT_ELEMENT_AUDIOTESTSRC "audiotestsrc" -#define DEFAULT_ELEMENT_APPSRC "appsrc" -#define DEFAULT_ELEMENT_SCREENSRC "waylandsrc" -#define DEFAULT_ELEMENT_VIDEOCONVERT "videoconvert" -#define DEFAULT_ELEMENT_CAPSFILTER "capsfilter" -#define DEFAULT_ELEMENT_QUEUE "queue" -#define DEFAULT_ELEMENT_VOLUME "volume" +#define DEFAULT_ELEMENT_CAMERASRC "v4l2src" +#define DEFAULT_ELEMENT_AUDIOSRC "pulsesrc" +#define DEFAULT_ELEMENT_VIDEOTESTSRC "videotestsrc" +#define DEFAULT_ELEMENT_AUDIOTESTSRC "audiotestsrc" +#define DEFAULT_ELEMENT_APPSRC "appsrc" +#define DEFAULT_ELEMENT_SCREENSRC "waylandsrc" +#define DEFAULT_ELEMENT_VIDEOCONVERT "videoconvert" +#define DEFAULT_ELEMENT_CAPSFILTER "capsfilter" +#define DEFAULT_ELEMENT_QUEUE "queue" +#define DEFAULT_ELEMENT_VOLUME "volume" +#define DEFAULT_ELEMENT_INPUT_SELECTOR "input-selector" #define ELEMENT_NAME_FIRST_CAPSFILTER "firstCapsfilter" +#define ELEMENT_NAME_RTP_CAPSFILTER "rtpCapsfilter" #define ELEMENT_NAME_VIDEO_SRC "videoSrc" #define ELEMENT_NAME_VIDEO_SWITCH "videoSwitch" #define ELEMENT_NAME_VIDEO_MUTE_SRC "videoMuteSrc" #define ELEMENT_NAME_VOLUME "volume" +#define APPEND_ELEMENT(x_list, x_element) \ +do { \ + if (!(x_element)) \ + break; \ + x_list = g_list_append(x_list, x_element); \ + LOG_DEBUG("%s is appended", GST_ELEMENT_NAME(x_element)); \ +} while (0) + +#define PREPEND_ELEMENT(x_list, x_element) \ +do { \ + if (!(x_element)) \ + break; \ + x_list = g_list_prepend(x_list, x_element); \ + LOG_DEBUG("%s is prepended", GST_ELEMENT_NAME(x_element)); \ +} while (0) + typedef enum { CODEC_TYPE_OPUS, CODEC_TYPE_VORBIS, @@ -616,9 +634,13 @@ static GstElement *__get_hw_encoder_element(webrtc_s *webrtc, webrtc_gst_slot_s return NULL; } -static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source, - GstElement **capsfilter, GstElement **encoder, GstElement **payloader, GstElement **queue, GstElement **capsfilter2) +static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool need_capsfilter, GList **element_list) { + GstElement *capsfilter = NULL; + GstElement *encoder; + GstElement *payloader; + GstElement *queue; + GstElement *capsfilter2; GstCaps *sink_caps; element_info_s elem_info; const gchar *encoder_klass_name; @@ -627,20 +649,16 @@ static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL"); - RET_VAL_IF(encoder == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "encoder is NULL"); - RET_VAL_IF(payloader == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "payloader is NULL"); - RET_VAL_IF(queue == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "queue is NULL"); - RET_VAL_IF(capsfilter2 == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "capsfilter2 is NULL"); + RET_VAL_IF(element_list == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "element_list is NULL"); - if (capsfilter) { - if (!(*capsfilter = _create_element(DEFAULT_ELEMENT_CAPSFILTER, ELEMENT_NAME_FIRST_CAPSFILTER))) { + if (need_capsfilter) { + if (!(capsfilter = _create_element(DEFAULT_ELEMENT_CAPSFILTER, ELEMENT_NAME_FIRST_CAPSFILTER))) { LOG_ERROR("failed to create capsfilter"); return WEBRTC_ERROR_INVALID_OPERATION; } if ((sink_caps = __make_default_raw_caps(source, &webrtc->ini))) { PRINT_CAPS(sink_caps, "capsfilter"); - - g_object_set(G_OBJECT(*capsfilter), "caps", sink_caps, NULL); + g_object_set(G_OBJECT(capsfilter), "caps", sink_caps, NULL); gst_caps_unref(sink_caps); } } @@ -655,18 +673,18 @@ static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source } if (source->zerocopy_enabled) - *encoder = __get_hw_encoder_element(webrtc, source); + encoder = __get_hw_encoder_element(webrtc, source); else CREATE_ELEMENT_FROM_REGISTRY(elem_info, encoder_klass_name, __make_default_raw_caps(source, &webrtc->ini), __make_default_encoded_caps(source, &webrtc->ini, NULL), - *encoder); - if (*encoder == NULL) + encoder); + if (encoder == NULL) return WEBRTC_ERROR_INVALID_OPERATION; - encoder_name = gst_element_get_name(*encoder); + encoder_name = gst_element_get_name(encoder); if (encoder_name && (!g_strcmp0(encoder_name, "vp8enc") || !g_strcmp0(encoder_name, "vp9enc"))) { - g_object_set(G_OBJECT(*encoder), "threads", webrtc->ini.vpxenc_params.threads, + g_object_set(G_OBJECT(encoder), "threads", webrtc->ini.vpxenc_params.threads, "end-usage", webrtc->ini.vpxenc_params.end_usage, "cpu-used", webrtc->ini.vpxenc_params.cpu_used, "target-bitrate", webrtc->ini.vpxenc_params.target_bitrate, @@ -680,30 +698,36 @@ static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source CREATE_ELEMENT_FROM_REGISTRY(elem_info, GST_KLASS_NAME_PAYLOADER_RTP, __make_default_encoded_caps(source, &webrtc->ini, &media_type), NULL, - *payloader); - if (*payloader == NULL) { + payloader); + if (payloader == NULL) { g_free(media_type); return WEBRTC_ERROR_INVALID_OPERATION; } - if (!(*queue = _create_element(DEFAULT_ELEMENT_QUEUE, NULL))) { + if (!(queue = _create_element(DEFAULT_ELEMENT_QUEUE, NULL))) { LOG_ERROR("failed to create queue"); g_free(media_type); return WEBRTC_ERROR_INVALID_OPERATION; } - if (!(*capsfilter2 = _create_element(DEFAULT_ELEMENT_CAPSFILTER, NULL))) { + if (!(capsfilter2 = _create_element(DEFAULT_ELEMENT_CAPSFILTER, ELEMENT_NAME_RTP_CAPSFILTER))) { LOG_ERROR("failed to create capsfilter"); g_free(media_type); return WEBRTC_ERROR_INVALID_OPERATION; } if ((sink_caps = __make_rtp_caps(media_type, source->id))) { - g_object_set(G_OBJECT(*capsfilter2), "caps", sink_caps, NULL); + g_object_set(G_OBJECT(capsfilter2), "caps", sink_caps, NULL); gst_caps_unref(sink_caps); } g_free(media_type); + APPEND_ELEMENT(*element_list, capsfilter); + APPEND_ELEMENT(*element_list, encoder); + APPEND_ELEMENT(*element_list, payloader); + APPEND_ELEMENT(*element_list, queue); + APPEND_ELEMENT(*element_list, capsfilter2); + return WEBRTC_ERROR_NONE; } @@ -833,41 +857,128 @@ static void __add_probe_to_pad(GstPad *pad, media_type_e media_type, webrtc_gst_ source->av[probe_userdata->av_idx].src_pad_probe_id, pad, probe_userdata->av_idx, source); } -static GstElement * __link_video_switch(GstBin *bin, GstElement *src) +static bool __add_elements_to_bin(GstBin *bin, GList *element_list) { - GstElement *videotestsrc = NULL; - GstElement *videoswitch = NULL; + GstElement *element; + GList *list; + int count = 0; - RET_VAL_IF(bin == NULL, NULL, "bin is NULL"); - RET_VAL_IF(src == NULL, NULL, "src is NULL"); + RET_VAL_IF(bin == NULL, false, "bin is NULL"); + RET_VAL_IF(element_list == NULL, false, "element_list is NULL"); - if (!(videotestsrc = _create_element(DEFAULT_ELEMENT_VIDEOTESTSRC, ELEMENT_NAME_VIDEO_MUTE_SRC))) - return NULL; + for (list = element_list; list; list = list->next) { + element = (GstElement *)list->data; + RET_VAL_IF(!gst_bin_add(bin, element), false, + "failed to gst_bin_add(), bin[%s], element[%s]", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(element)); + count++; + } - g_object_set(G_OBJECT(videotestsrc), "is-live", TRUE, "pattern", 2, NULL); /* 2: black */ + LOG_DEBUG("%d elements are added to bin[%s]", count, GST_ELEMENT_NAME(bin)); - if (!(videoswitch = _create_element("input-selector", ELEMENT_NAME_VIDEO_SWITCH))) { - SAFE_GST_OBJECT_UNREF(videotestsrc); - return NULL; + return true; +} + +static bool __remove_elements_from_bin(GstBin *bin, GList *element_list) +{ + GstElement *element; + GList *list; + int count = 0; + + RET_VAL_IF(bin == NULL, false, "bin is NULL"); + RET_VAL_IF(element_list == NULL, false, "element_list is NULL"); + + for (list = element_list; list; list = g_list_next(list)) { + element = (GstElement *)list->data; + RET_VAL_IF(!gst_bin_remove(bin, element), false, + "failed to gst_bin_remove(), bin[%s], element[%s]", GST_ELEMENT_NAME(bin), GST_ELEMENT_NAME(element)); + count++; } - gst_bin_add_many(bin, videotestsrc, videoswitch, NULL); + LOG_DEBUG("%d elements are removed from bin[%s]", count, GST_ELEMENT_NAME(bin)); + + return true; +} + +static void __unref_elements(GList *element_list) +{ + GList *list; + + if (!element_list) + return; + + for (list = element_list; list; list = g_list_next(list)) + SAFE_GST_OBJECT_UNREF(list->data); +} + +static bool __link_elements(GList *element_list) +{ + GstElement *curr; + GstElement *prev = NULL; + GList *list; + int count = 0; + + RET_VAL_IF(element_list == NULL, false, "element_list is NULL"); + + for (list = element_list; list; list = g_list_next(list)) { + if (!g_list_previous(list)) + continue; + prev = (GstElement *)(g_list_previous(list)->data); + curr = (GstElement *)list->data; + RET_VAL_IF(!gst_element_link(prev, curr), false, + "failed to gst_element_link(), [%s] - [%s]", GST_ELEMENT_NAME(prev), GST_ELEMENT_NAME(curr)); + LOG_DEBUG("[%s] - [%s]", GST_ELEMENT_NAME(prev), GST_ELEMENT_NAME(curr)); + count++; + } + + LOG_DEBUG("%d elements are linked", count); + + return true; +} + +static bool __link_switch_srcs(GstElement *switch_element, GList *switch_src_list) +{ + GstElement *element; + GList *list; + + RET_VAL_IF(switch_element == NULL, false, "switch_element is NULL"); + RET_VAL_IF(switch_src_list == NULL, false, "switch_src_list is NULL"); - gst_element_link(src, videoswitch); - gst_element_link(videotestsrc, videoswitch); + for (list = switch_src_list; list; list = g_list_next(list)) { + element = (GstElement *)list->data; + RET_VAL_IF(!gst_element_link(element, switch_element), false, + "failed to gst_element_link(), [%s] - [%s]", GST_ELEMENT_NAME(element), GST_ELEMENT_NAME(switch_element)); - return videoswitch; + LOG_DEBUG("[%s] - [%s]", GST_ELEMENT_NAME(element), GST_ELEMENT_NAME(switch_element)); + } + + return true; } -static void __unlink_video_switch(GstBin *bin) +static GstElement *__find_element_in_bin(GstBin *bin, const gchar *name) { - GstElement *videotestsrc = NULL; - GstElement *videoswitch = NULL; + GValue value = G_VALUE_INIT; + GstElement *element; + GstIterator *bin_iterator; - videotestsrc = gst_bin_get_by_name(bin, ELEMENT_NAME_VIDEO_MUTE_SRC); - videoswitch = gst_bin_get_by_name(bin, ELEMENT_NAME_VIDEO_SWITCH); + RET_VAL_IF(bin == NULL, NULL, "bin is NULL"); + RET_VAL_IF(name == NULL, NULL, "name is NULL"); + RET_VAL_IF(!(bin_iterator = gst_bin_iterate_sorted(bin)), NULL, "bin_iterator is NULL"); - gst_bin_remove_many(bin, videotestsrc, videoswitch, NULL); + while (GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &value)) { + element = GST_ELEMENT(g_value_get_object(&value)); + + if (g_strrstr(GST_ELEMENT_NAME(element), name)) { + LOG_DEBUG("found element by name [%s]", GST_ELEMENT_NAME(element)); + gst_iterator_free(bin_iterator); + return element; + } + + g_value_reset(&value); + } + + gst_iterator_free(bin_iterator); + + return NULL; } static int __build_screensrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) @@ -875,12 +986,11 @@ static int __build_screensrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) int ret = WEBRTC_ERROR_NONE; GstElement *screensrc; GstElement *videoconvert; - GstElement *capsfilter = NULL; - GstElement *videoenc = NULL; - GstElement *videopay = NULL; - GstElement *queue = NULL; - GstElement *capsfilter2 = NULL; - GstElement *video_switch = NULL; + GstElement *videotestsrc; + GstElement *videoswitch; + GstElement *capsfilter; + GList *switch_src_list = NULL; + GList *element_list = NULL; RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL"); @@ -894,46 +1004,70 @@ static int __build_screensrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) if (!(screensrc = _create_element(__get_source_element(webrtc, WEBRTC_MEDIA_SOURCE_TYPE_SCREEN), ELEMENT_NAME_VIDEO_SRC))) return WEBRTC_ERROR_INVALID_OPERATION; + APPEND_ELEMENT(switch_src_list, screensrc); + + if (!(videotestsrc = _create_element(DEFAULT_ELEMENT_VIDEOTESTSRC, ELEMENT_NAME_VIDEO_MUTE_SRC))) + goto exit; + APPEND_ELEMENT(switch_src_list, videotestsrc); + + g_object_set(G_OBJECT(videotestsrc), "is-live", TRUE, "pattern", 2, NULL); /* 2: black */ + + if (!(videoswitch = _create_element(DEFAULT_ELEMENT_INPUT_SELECTOR, ELEMENT_NAME_VIDEO_SWITCH))) + goto exit; + APPEND_ELEMENT(element_list, videoswitch); if (!(videoconvert = _create_element(DEFAULT_ELEMENT_VIDEOCONVERT, NULL))) goto exit; + APPEND_ELEMENT(element_list, videoconvert); - if ((ret = __create_rest_of_elements(webrtc, source, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE) + if ((ret = __create_rest_of_elements(webrtc, source, true, &element_list)) != WEBRTC_ERROR_NONE) goto exit; - gst_bin_add_many(source->bin, screensrc, videoconvert, capsfilter, videoenc, videopay, queue, capsfilter2, NULL); + if (!__add_elements_to_bin(source->bin, switch_src_list)) + goto exit; - video_switch = __link_video_switch(source->bin, screensrc); - if (!video_switch) + if (!__add_elements_to_bin(source->bin, element_list)) { + ret = WEBRTC_ERROR_INVALID_OPERATION; goto exit_with_remove_from_bin; + } - if (!gst_element_link_many(video_switch, videoconvert, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) { - LOG_ERROR("failed to gst_element_link_many()"); + if (!__link_switch_srcs(videoswitch, switch_src_list)) { + ret = WEBRTC_ERROR_INVALID_OPERATION; + goto exit_with_remove_from_bin; + } + + if (!__link_elements(element_list)) { ret = WEBRTC_ERROR_INVALID_OPERATION; goto exit_with_remove_from_bin; } - ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter2, true); + if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) { + ret = WEBRTC_ERROR_INVALID_OPERATION; + goto exit_with_remove_from_bin; + } + ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter, true); if (ret != WEBRTC_ERROR_NONE) goto exit_with_remove_from_bin; __add_probe_to_pad(source->av[AV_IDX_VIDEO].src_pad, MEDIA_TYPE_VIDEO, source); + SAFE_G_LIST_FREE(switch_src_list); + SAFE_G_LIST_FREE(element_list); + return WEBRTC_ERROR_NONE; exit_with_remove_from_bin: /* elements will be dereferenced */ - gst_bin_remove_many(source->bin, screensrc, videoconvert, capsfilter, videoenc, videopay, queue, capsfilter2, NULL); - __unlink_video_switch(source->bin); + __remove_elements_from_bin(source->bin, switch_src_list); + __remove_elements_from_bin(source->bin, element_list); + SAFE_G_LIST_FREE(switch_src_list); + SAFE_G_LIST_FREE(element_list); return ret; exit: - SAFE_GST_OBJECT_UNREF(screensrc); - SAFE_GST_OBJECT_UNREF(videoconvert); - SAFE_GST_OBJECT_UNREF(capsfilter); - SAFE_GST_OBJECT_UNREF(videoenc); - SAFE_GST_OBJECT_UNREF(videopay); - SAFE_GST_OBJECT_UNREF(queue); - SAFE_GST_OBJECT_UNREF(capsfilter2); + __unref_elements(switch_src_list); + __unref_elements(element_list); + SAFE_G_LIST_FREE(switch_src_list); + SAFE_G_LIST_FREE(element_list); return ret; } @@ -941,11 +1075,8 @@ static int __build_camerasrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) { int ret = WEBRTC_ERROR_NONE; GstElement *camerasrc; - GstElement *capsfilter = NULL; - GstElement *videoenc = NULL; - GstElement *videopay = NULL; - GstElement *queue = NULL; - GstElement *capsfilter2 = NULL; + GstElement *capsfilter; + GList *element_list = NULL; RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL"); @@ -961,6 +1092,7 @@ static int __build_camerasrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) #endif if (!(camerasrc = _create_element(__get_source_element(webrtc, WEBRTC_MEDIA_SOURCE_TYPE_CAMERA), ELEMENT_NAME_VIDEO_SRC))) return WEBRTC_ERROR_INVALID_OPERATION; + APPEND_ELEMENT(element_list, camerasrc); /* FIXME: set camera default setting from ini */ @@ -969,49 +1101,50 @@ static int __build_camerasrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) if (g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(camerasrc)), "empty-buffer-timeout")) g_object_set(G_OBJECT(camerasrc), "empty-buffer-timeout", 0, NULL); - if ((ret = __create_rest_of_elements(webrtc, source, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE) + if ((ret = __create_rest_of_elements(webrtc, source, true, &element_list)) != WEBRTC_ERROR_NONE) goto exit; - gst_bin_add_many(source->bin, camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL); - if (!gst_element_link_many(camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) { - LOG_ERROR("failed to gst_element_link_many()"); + if (!__add_elements_to_bin(source->bin, element_list)) + goto exit; + + if (!__link_elements(element_list)) { ret = WEBRTC_ERROR_INVALID_OPERATION; goto exit_with_remove_from_bin; } - ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter2, true); + if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) { + ret = WEBRTC_ERROR_INVALID_OPERATION; + goto exit_with_remove_from_bin; + } + ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter, true); if (ret != WEBRTC_ERROR_NONE) goto exit_with_remove_from_bin; __add_probe_to_pad(source->av[AV_IDX_VIDEO].src_pad, MEDIA_TYPE_VIDEO, source); + SAFE_G_LIST_FREE(element_list); + return WEBRTC_ERROR_NONE; exit_with_remove_from_bin: /* elements will be dereferenced */ - gst_bin_remove_many(source->bin, camerasrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL); + __remove_elements_from_bin(source->bin, element_list); + SAFE_G_LIST_FREE(element_list); return ret; exit: - SAFE_GST_OBJECT_UNREF(camerasrc); - SAFE_GST_OBJECT_UNREF(capsfilter); - SAFE_GST_OBJECT_UNREF(videoenc); - SAFE_GST_OBJECT_UNREF(videopay); - SAFE_GST_OBJECT_UNREF(queue); - SAFE_GST_OBJECT_UNREF(capsfilter2); + __unref_elements(element_list); + SAFE_G_LIST_FREE(element_list); return ret; } -static int __build_audiosrc(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool is_mic) +static int __build_audiosrc(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool use_mic) { int ret = WEBRTC_ERROR_NONE; const char *source_factory_name; GstElement *audiosrc; - GstElement *volume = NULL; - GstElement *capsfilter = NULL; - GstElement *audioenc = NULL; - GstElement *audiopay = NULL; - GstElement *queue = NULL; - GstElement *capsfilter2 = NULL; + GstElement *volume; + GstElement *capsfilter; + GList *element_list = NULL; RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL"); @@ -1023,46 +1156,51 @@ static int __build_audiosrc(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool is source->media_types = MEDIA_TYPE_AUDIO; source->zerocopy_enabled = __is_hw_encoder_used(webrtc, source->type, source->media_types); - source_factory_name = __get_source_element(webrtc, is_mic ? WEBRTC_MEDIA_SOURCE_TYPE_MIC : WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST); + source_factory_name = __get_source_element(webrtc, use_mic ? WEBRTC_MEDIA_SOURCE_TYPE_MIC : WEBRTC_MEDIA_SOURCE_TYPE_AUDIOTEST); if (!(audiosrc = _create_element(source_factory_name, NULL))) return WEBRTC_ERROR_INVALID_OPERATION; + APPEND_ELEMENT(element_list, audiosrc); - if (!is_mic) + if (!use_mic) g_object_set(G_OBJECT(audiosrc), "is-live", TRUE, NULL); if (!(volume = _create_element(DEFAULT_ELEMENT_VOLUME, ELEMENT_NAME_VOLUME))) goto exit; + APPEND_ELEMENT(element_list, volume); - if ((ret = __create_rest_of_elements(webrtc, source, &capsfilter, &audioenc, &audiopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE) + if ((ret = __create_rest_of_elements(webrtc, source, true, &element_list)) != WEBRTC_ERROR_NONE) goto exit; - gst_bin_add_many(source->bin, audiosrc, volume, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL); - if (!gst_element_link_many(audiosrc, volume, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL)) { - LOG_ERROR("failed to gst_element_link_many()"); + if (!__add_elements_to_bin(source->bin, element_list)) + goto exit; + + if (!__link_elements(element_list)) { ret = WEBRTC_ERROR_INVALID_OPERATION; goto exit_with_remove_from_bin; } - ret = _set_ghost_pad_target(source->av[AV_IDX_AUDIO].src_pad, capsfilter2, true); + if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) { + ret = WEBRTC_ERROR_INVALID_OPERATION; + goto exit_with_remove_from_bin; + } + ret = _set_ghost_pad_target(source->av[AV_IDX_AUDIO].src_pad, capsfilter, true); if (ret != WEBRTC_ERROR_NONE) goto exit_with_remove_from_bin; __add_probe_to_pad(source->av[AV_IDX_AUDIO].src_pad, MEDIA_TYPE_AUDIO, source); + SAFE_G_LIST_FREE(element_list); + return WEBRTC_ERROR_NONE; exit_with_remove_from_bin: /* elements will be dereferenced */ - gst_bin_remove_many(source->bin, audiosrc, volume, capsfilter, audioenc, audiopay, queue, capsfilter2, NULL); + __remove_elements_from_bin(source->bin, element_list); + SAFE_G_LIST_FREE(element_list); return ret; exit: - SAFE_GST_OBJECT_UNREF(audiosrc); - SAFE_GST_OBJECT_UNREF(volume); - SAFE_GST_OBJECT_UNREF(capsfilter); - SAFE_GST_OBJECT_UNREF(audioenc); - SAFE_GST_OBJECT_UNREF(audiopay); - SAFE_GST_OBJECT_UNREF(queue); - SAFE_GST_OBJECT_UNREF(capsfilter2); + __unref_elements(element_list); + SAFE_G_LIST_FREE(element_list); return ret; } @@ -1070,11 +1208,8 @@ static int __build_videotestsrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) { int ret = WEBRTC_ERROR_NONE; GstElement *videotestsrc; - GstElement *capsfilter = NULL; - GstElement *videoenc = NULL; - GstElement *videopay = NULL; - GstElement *queue = NULL; - GstElement *capsfilter2 = NULL; + GstElement *capsfilter; + GList *element_list = NULL; RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL"); @@ -1088,38 +1223,43 @@ static int __build_videotestsrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) if (!(videotestsrc = _create_element(__get_source_element(webrtc, WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST), ELEMENT_NAME_VIDEO_SRC))) return WEBRTC_ERROR_INVALID_OPERATION; + APPEND_ELEMENT(element_list, videotestsrc); g_object_set(G_OBJECT(videotestsrc), "is-live", TRUE, "pattern", 18, NULL); /* 18: ball */ - if ((ret = __create_rest_of_elements(webrtc, source, &capsfilter, &videoenc, &videopay, &queue, &capsfilter2)) != WEBRTC_ERROR_NONE) + if ((ret = __create_rest_of_elements(webrtc, source, true, &element_list)) != WEBRTC_ERROR_NONE) goto exit; - gst_bin_add_many(source->bin, videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL); - if (!gst_element_link_many(videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL)) { - LOG_ERROR("failed to gst_element_link_many()"); + if (!__add_elements_to_bin(source->bin, element_list)) + goto exit; + + if (!__link_elements(element_list)) { ret = WEBRTC_ERROR_INVALID_OPERATION; goto exit_with_remove_from_bin; } - ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter2, true); + if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) { + ret = WEBRTC_ERROR_INVALID_OPERATION; + goto exit_with_remove_from_bin; + } + ret = _set_ghost_pad_target(source->av[AV_IDX_VIDEO].src_pad, capsfilter, true); if (ret != WEBRTC_ERROR_NONE) goto exit_with_remove_from_bin; __add_probe_to_pad(source->av[AV_IDX_VIDEO].src_pad, MEDIA_TYPE_VIDEO, source); + SAFE_G_LIST_FREE(element_list); + return WEBRTC_ERROR_NONE; exit_with_remove_from_bin: /* elements will be dereferenced */ - gst_bin_remove_many(source->bin, videotestsrc, capsfilter, videoenc, videopay, queue, capsfilter2, NULL); + __remove_elements_from_bin(source->bin, element_list); + SAFE_G_LIST_FREE(element_list); return ret; exit: - SAFE_GST_OBJECT_UNREF(videotestsrc); - SAFE_GST_OBJECT_UNREF(capsfilter); - SAFE_GST_OBJECT_UNREF(videoenc); - SAFE_GST_OBJECT_UNREF(videopay); - SAFE_GST_OBJECT_UNREF(queue); - SAFE_GST_OBJECT_UNREF(capsfilter2); + __unref_elements(element_list); + SAFE_G_LIST_FREE(element_list); return ret; } @@ -1186,43 +1326,13 @@ static int __build_mediapacketsrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) return WEBRTC_ERROR_NONE; } -static GstElement *__find_element_in_bin(GstBin *bin, const gchar *name) -{ - GValue value = G_VALUE_INIT; - GstElement *element; - GstIterator *bin_iterator; - - RET_VAL_IF(bin == NULL, NULL, "bin is NULL"); - RET_VAL_IF(name == NULL, NULL, "name is NULL"); - - bin_iterator = gst_bin_iterate_sorted(bin); - - while (GST_ITERATOR_OK == gst_iterator_next(bin_iterator, &value)) { - element = GST_ELEMENT(g_value_get_object(&value)); - - if (g_strrstr(GST_ELEMENT_NAME(element), name)) { - LOG_DEBUG("found element by name [%s]", GST_ELEMENT_NAME(element)); - gst_iterator_free(bin_iterator); - return element; - } - - g_value_reset(&value); - } - - gst_iterator_free(bin_iterator); - - return NULL; -} - static int __complete_mediapacketsrc_from_raw_format(webrtc_s *webrtc, webrtc_gst_slot_s *source) { int ret = WEBRTC_ERROR_NONE; GstPad **src_pad; GstElement *appsrc; - GstElement *encoder; - GstElement *payloader; - GstElement *queue; GstElement *capsfilter; + GList *element_list = NULL; GstCaps *sink_caps; RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); @@ -1238,7 +1348,7 @@ static int __complete_mediapacketsrc_from_raw_format(webrtc_s *webrtc, webrtc_gs source->zerocopy_enabled = __is_hw_encoder_used(webrtc, source->type, source->media_types); - if ((ret = __create_rest_of_elements(webrtc, source, NULL, &encoder, &payloader, &queue, &capsfilter)) != WEBRTC_ERROR_NONE) + if ((ret = __create_rest_of_elements(webrtc, source, false, &element_list)) != WEBRTC_ERROR_NONE) return ret; if (!(sink_caps = __make_raw_caps_from_media_format(source))) { @@ -1250,13 +1360,34 @@ static int __complete_mediapacketsrc_from_raw_format(webrtc_s *webrtc, webrtc_gs g_object_set(G_OBJECT(appsrc), "caps", sink_caps, NULL); gst_caps_unref(sink_caps); - gst_bin_add_many(source->bin, encoder, payloader, queue, capsfilter, NULL); - if (!gst_element_link_many(appsrc, encoder, payloader, queue, capsfilter, NULL)) { - LOG_ERROR("failed to gst_element_link_many()"); - return WEBRTC_ERROR_INVALID_OPERATION; + if (!__add_elements_to_bin(source->bin, element_list)) + goto exit; + + PREPEND_ELEMENT(element_list, appsrc); + if (!__link_elements(element_list)) { + ret = WEBRTC_ERROR_INVALID_OPERATION; + goto exit_with_remove_from_bin; } + if (!(capsfilter = gst_bin_get_by_name(source->bin, ELEMENT_NAME_RTP_CAPSFILTER))) { + element_list = g_list_nth(element_list, 1); /* skip removing appsrc from bin */ + ret = WEBRTC_ERROR_INVALID_OPERATION; + goto exit_with_remove_from_bin; + } + + SAFE_G_LIST_FREE(element_list); + return _set_ghost_pad_target(*src_pad, capsfilter, true); + +exit_with_remove_from_bin: + /* elements will be dereferenced */ + __remove_elements_from_bin(source->bin, element_list); + SAFE_G_LIST_FREE(element_list); + return ret; +exit: + __unref_elements(element_list); + SAFE_G_LIST_FREE(element_list); + return ret; } static GstCaps *__make_encoded_caps_for_appsrc(webrtc_gst_slot_s *source) -- 2.34.1