From fa9c23ff2fee7174d7e2ae37b011e12e4851c38d Mon Sep 17 00:00:00 2001 From: Sangchul Lee Date: Mon, 15 Jun 2020 10:49:26 +0900 Subject: [PATCH] Improve media_streamer_node_set_pad_format() for WebRTC node The previous codes can not propagate the pad event because the pipeline status is not satisfied with the condition to set the pad format normally. To fix it, a capsfilter element is added in the creation time of WebRTC node and set new caps to its property. A ghost pad for the audio input is newly added to WebRTC node. [Version] 0.1.63 [Issue Type] Bug fix Change-Id: I624bca9c0c4376d38587f0dd49e94c6f7e90ee6a Signed-off-by: Sangchul Lee --- packaging/capi-media-streamer.spec | 2 +- src/media_streamer_gst_webrtc.c | 16 +--- src/media_streamer_node.c | 146 ++++++++++++++++++++++++++++++++++++- 3 files changed, 147 insertions(+), 17 deletions(-) diff --git a/packaging/capi-media-streamer.spec b/packaging/capi-media-streamer.spec index ef8ad8b..ae2c48b 100644 --- a/packaging/capi-media-streamer.spec +++ b/packaging/capi-media-streamer.spec @@ -1,6 +1,6 @@ Name: capi-media-streamer Summary: A Media Streamer API -Version: 0.1.62 +Version: 0.1.63 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/media_streamer_gst_webrtc.c b/src/media_streamer_gst_webrtc.c index dc354de..4c5da00 100644 --- a/src/media_streamer_gst_webrtc.c +++ b/src/media_streamer_gst_webrtc.c @@ -630,7 +630,6 @@ GstElement *ms_webrtc_element_create(void) { GstElement *webrtc_container; GstElement *webrtcbin; - GstGhostPad *ghost_pad_video_in; ms_debug_fenter(); @@ -651,22 +650,11 @@ GstElement *ms_webrtc_element_create(void) ms_error("Failed to create webrtcbin element"); return NULL; } - g_object_set(G_OBJECT(webrtcbin), "stun-server", DEFAULT_WEBRTC_STUN_SERVER, NULL); - /* FIXME: should it be set by user? */ g_object_set(G_OBJECT(webrtcbin), "bundle-policy", 3, NULL); // 3:max-bundle - - ms_bin_add_element(webrtc_container, webrtcbin, FALSE); - - if (!(ghost_pad_video_in = (GstGhostPad *)gst_element_get_static_pad(webrtc_container, MS_RTP_PAD_VIDEO_IN))) { - ms_error("Failed to get ghost pad for webrtc_container"); - return NULL; - } - - if (!(gst_ghost_pad_set_target(ghost_pad_video_in, gst_element_get_request_pad(webrtcbin, "sink_%u")))) { - ms_info("Failed to gst_ghost_pad_set_target() for %s", MS_RTP_PAD_VIDEO_IN); - /* release resources */ + if (!ms_bin_add_element(webrtc_container, webrtcbin, FALSE)) { + ms_error("Failed to add webrtcbin to webrtc_container"); return NULL; } diff --git a/src/media_streamer_node.c b/src/media_streamer_node.c index 53f4c37..ad8fa4e 100644 --- a/src/media_streamer_node.c +++ b/src/media_streamer_node.c @@ -34,6 +34,9 @@ #define _FEATURE_NAME_CAMERA "http://tizen.org/feature/camera" #define _FEATURE_NAME_MICROPHONE "http://tizen.org/feature/microphone" +#define _WEBRTC_AUDIO_CAPSFILTER "audio_capsfilter" +#define _WEBRTC_VIDEO_CAPSFILTER "video_capsfilter" + static param_s param_table[] = { {MEDIA_STREAMER_PARAM_CAMERA_ID, "camera-id"}, {MEDIA_STREAMER_PARAM_CAPTURE_WIDTH, "capture-width"}, @@ -1519,8 +1522,74 @@ int ms_rtp_node_prepare(media_streamer_node_s *node) return MEDIA_STREAMER_ERROR_NONE; } +static int __ms_webrtc_prepare_ghost_sink_pad(GstElement *webrtc_container, GstElement *webrtcbin, const char *capsfilter_name) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + GstElement *filter; + GstGhostPad *ghost_pad_in = NULL; + GstPad *filter_sink_pad = NULL; + GstPad *req_pad; + gchar *req_pad_name; + const gchar *pad_name; + + ms_retvm_if(!webrtc_container, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtc_container is NULL"); + ms_retvm_if(!webrtcbin, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "webrtcbin is NULL"); + ms_retvm_if(!capsfilter_name, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "capsfilter_name is NULL"); + + if (g_strcmp0(capsfilter_name, _WEBRTC_AUDIO_CAPSFILTER) && + g_strcmp0(capsfilter_name, _WEBRTC_VIDEO_CAPSFILTER)) + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + + pad_name = !g_strcmp0(capsfilter_name, _WEBRTC_AUDIO_CAPSFILTER) ? MS_RTP_PAD_AUDIO_IN : MS_RTP_PAD_VIDEO_IN; + + if (!(filter = ms_find_element_in_bin_by_name(webrtc_container, capsfilter_name))) { + ms_debug("No need to export the ghost sink pad for [%s]", pad_name); + return MEDIA_STREAMER_ERROR_NONE; + } + + ms_info("%s is found, link it with webrtcbin and export the ghost pad[%s] of webrtc_container", + capsfilter_name, pad_name); + + if (!(req_pad = gst_element_get_request_pad(webrtcbin, "sink_%u"))) { + ms_error("Failed to get request pad"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + if (!(req_pad_name = gst_pad_get_name(req_pad))) { + ms_error("Failed to get request pad name"); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + if (!gst_element_link_pads(filter, "src", webrtcbin, req_pad_name)) { + ms_error("Failed to link pads, %s - webrtcbin", capsfilter_name); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto end; + } + if (!(ghost_pad_in = (GstGhostPad *)gst_element_get_static_pad(webrtc_container, pad_name))) { + ms_error("Failed to get ghost pad for webrtc_container"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto end; + } + if (!(filter_sink_pad = gst_element_get_static_pad(filter, "sink"))) { + ms_error("Failed to get capsfilter sink pad in webrtc_container"); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto end; + } + if (!gst_ghost_pad_set_target(ghost_pad_in, filter_sink_pad)) { + ms_info("Failed to gst_ghost_pad_set_target() for %s", pad_name); + ret = MEDIA_STREAMER_ERROR_INVALID_OPERATION; + goto end; + } + +end: + MS_SAFE_GFREE(req_pad_name); + MS_SAFE_UNREF(filter_sink_pad); + MS_SAFE_UNREF(ghost_pad_in); + + return ret; +} + int ms_webrtc_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s *node) { + int ret = MEDIA_STREAMER_ERROR_NONE; GstElement *webrtcbin = NULL; node_info_s *node_klass_type = NULL; GObject *send_channel = NULL; @@ -1545,6 +1614,11 @@ int ms_webrtc_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s return MEDIA_STREAMER_ERROR_INVALID_OPERATION; } + if ((ret = __ms_webrtc_prepare_ghost_sink_pad(node->gst_element, webrtcbin, _WEBRTC_AUDIO_CAPSFILTER))) + return ret; + if ((ret = __ms_webrtc_prepare_ghost_sink_pad(node->gst_element, webrtcbin, _WEBRTC_VIDEO_CAPSFILTER))) + return ret; + if (__ms_webrtc_node_is_offerer(node, &is_offerer)) { ms_error("Failed to get peer type"); return MEDIA_STREAMER_ERROR_INVALID_OPERATION; @@ -1576,7 +1650,6 @@ int ms_webrtc_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s return MEDIA_STREAMER_ERROR_NONE; } - //LCOV_EXCL_STOP int ms_demux_node_prepare(media_streamer_s *ms_streamer, media_streamer_node_s *node) @@ -1928,6 +2001,75 @@ static int __ms_rtp_node_set_pad_format(media_streamer_node_s *node, const char return ret; } +static int __ms_webrtc_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, media_format_h fmt) +{ + int ret = MEDIA_STREAMER_ERROR_NONE; + media_format_mimetype_e mime; + const gchar *encoding_name = NULL; + const gchar *capsfilter_name = NULL; + gchar *caps_str = NULL; + gchar *media = NULL; + gint payload = 0; + GstCaps *caps = NULL; + GstElement *capsfilter = NULL; + + ms_retvm_if(node == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node is NULL"); + ms_retvm_if(node->gst_element == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "node's element is NULL"); + ms_retvm_if(pad_name == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "pad_name is NULL"); + ms_retvm_if(fmt == NULL, MEDIA_STREAMER_ERROR_INVALID_PARAMETER, "fmt is NULL"); + + ms_debug_fenter(); + + if (!g_strrstr(pad_name, MS_RTP_PAD_VIDEO_IN) && !g_strrstr(pad_name, MS_RTP_PAD_AUDIO_IN)) { + ms_error("Not supported pad_name(%s)", pad_name); + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + } + + if (g_strrstr(pad_name, MS_RTP_PAD_VIDEO_IN) && + !media_format_get_video_info(fmt, &mime, NULL, NULL, NULL, NULL)) { + media = "video"; + payload = 96; + capsfilter_name = _WEBRTC_VIDEO_CAPSFILTER; + } else if (g_strrstr(pad_name, MS_RTP_PAD_AUDIO_IN) && + !media_format_get_audio_info(fmt, &mime, NULL, NULL, NULL, NULL)) { + media = "audio"; + payload = 97; + capsfilter_name = _WEBRTC_AUDIO_CAPSFILTER; + } else { + ms_error("Invalid media format for pad_name(%s)", pad_name); + return MEDIA_STREAMER_ERROR_INVALID_PARAMETER; + } + + encoding_name = ms_convert_mime_to_rtp_format(mime); + caps = gst_caps_new_simple("application/x-rtp", + "media", G_TYPE_STRING, media, + "encoding-name", G_TYPE_STRING, encoding_name, + "payload", G_TYPE_INT, payload, NULL); + + if (!(capsfilter = ms_find_element_in_bin_by_name(node->gst_element, capsfilter_name))) { + ms_debug("Create %s", capsfilter_name); + + if (!(capsfilter = ms_element_create("capsfilter", capsfilter_name))) { + ms_error("Failed to create capsfilter element: %s", capsfilter_name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + if (!ms_bin_add_element(node->gst_element, capsfilter, FALSE)) { + ms_error("Failed to add capsfilter(%s) to webrtc_container", capsfilter_name); + return MEDIA_STREAMER_ERROR_INVALID_OPERATION; + } + } + + g_object_set(G_OBJECT(capsfilter), "caps", (GValue *)caps, NULL); + + caps_str = gst_caps_to_string(caps); + ms_info("[%s] is set to [%s]", caps_str, capsfilter_name); + MS_SAFE_GFREE(caps_str); + + gst_caps_unref(caps); + + return ret; +} + int ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, media_format_h fmt) { int ret = MEDIA_STREAMER_ERROR_NONE; @@ -1942,7 +2084,7 @@ int ms_node_set_pad_format(media_streamer_node_s *node, const char *pad_name, me if (node->type == MEDIA_STREAMER_NODE_TYPE_RTP) ret = __ms_rtp_node_set_pad_format(node, pad_name, fmt); else if (node->type == MEDIA_STREAMER_NODE_TYPE_WEBRTC) - ret = ms_webrtcbin_set_pad_format(node->gst_element, pad_name, fmt); + ret = __ms_webrtc_node_set_pad_format(node, pad_name, fmt); else ret = ms_element_set_fmt(node->gst_element, pad_name, fmt); -- 2.7.4