From: Sangchul Lee Date: Wed, 27 Jul 2022 03:06:46 +0000 (+0900) Subject: Add API to set/get encoder bitrate X-Git-Tag: submit/tizen/20220805.110513~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F52%2F278852%2F8;p=platform%2Fcore%2Fapi%2Fwebrtc.git Add API to set/get encoder bitrate Functions are added as below. - webrtc_media_source_set_encoder_bitrate() - webrtc_media_source_get_encoder_bitrate() [Version] 0.3.191 [Issue Type] API Change-Id: I038da91a4ea00e4acac3f92d52a33b8c81ad6e29 Signed-off-by: Sangchul Lee --- diff --git a/include/webrtc.h b/include/webrtc.h index 18b4cb85..0cb403a3 100644 --- a/include/webrtc.h +++ b/include/webrtc.h @@ -1247,6 +1247,46 @@ int webrtc_media_source_set_mute(webrtc_h webrtc, unsigned int source_id, webrtc */ int webrtc_media_source_get_mute(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, bool *muted); +/** + * @brief Sets an encoder target bitrate(in bits/sec) to the media source. + * @details If @a source_id is a media source of #WEBRTC_MEDIA_SOURCE_TYPE_FILE or #WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET or #WEBRTC_MEDIA_SOURCE_TYPE_NULL, + * this function will return #WEBRTC_ERROR_INVALID_PARAMETER. + * @since_tizen 7.0 + * @param[in] webrtc WebRTC handle + * @param[in] source_id The media source id + * @param[in] media_type The media type + * @param[in] target_bitrate The target bitrate of the encoder + * @return @c 0 on success, + * otherwise a negative error value + * @retval #WEBRTC_ERROR_NONE Successful + * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation + * @pre Add media source to @a webrtc to get @a source_id by calling webrtc_add_media_source(). + * @see webrtc_add_media_source() + * @see webrtc_media_source_get_encoder_bitrate() + */ +int webrtc_media_source_set_encoder_bitrate(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, int target_bitrate); + +/** + * @brief Gets the encoder target bitrate(in bits/sec) of the media source. + * @details If @a source_id is a media source of #WEBRTC_MEDIA_SOURCE_TYPE_FILE or #WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET or #WEBRTC_MEDIA_SOURCE_TYPE_NULL, + * this function will return #WEBRTC_ERROR_INVALID_PARAMETER. + * @since_tizen 7.0 + * @param[in] webrtc WebRTC handle + * @param[in] source_id The media source id + * @param[in] media_type The media type + * @param[out] target_bitrate The target bitrate of the encoder + * @return @c 0 on success, + * otherwise a negative error value + * @retval #WEBRTC_ERROR_NONE Successful + * @retval #WEBRTC_ERROR_INVALID_PARAMETER Invalid parameter + * @retval #WEBRTC_ERROR_INVALID_OPERATION Invalid operation + * @pre Add media source to @a webrtc to get @a source_id by calling webrtc_add_media_source(). + * @see webrtc_add_media_source() + * @see webrtc_media_source_set_encoder_bitrate() + */ +int webrtc_media_source_get_encoder_bitrate(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, int *target_bitrate); + /** * @brief Sets a video resolution to the media source. * @details The following media source types contain video:\n diff --git a/include/webrtc_private.h b/include/webrtc_private.h index ccba09ff..f0fdbb22 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -528,6 +528,7 @@ typedef struct _webrtc_gst_slot_s { GstPad *src_pad; gulong src_pad_probe_id; gchar *raw_format; + int target_bitrate; bool pause; bool mute; bool inbandfec; @@ -687,6 +688,8 @@ int _set_audio_mute(webrtc_s *webrtc, unsigned int source_id, bool mute); int _get_audio_mute(webrtc_s *webrtc, unsigned int source_id, bool *muted); int _set_video_mute(webrtc_s *webrtc, unsigned int source_id, bool mute); int _get_video_mute(webrtc_s *webrtc, unsigned int source_id, bool *muted); +int _set_encoder_bitrate(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, int target_bitrate); +int _get_encoder_bitrate(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, int *target_bitrate); int _set_video_resolution(webrtc_s *webrtc, unsigned int source_id, int width, int height); int _get_video_resolution(webrtc_s *webrtc, unsigned int source_id, int *width, int *height); int _set_video_framerate(webrtc_s *webrtc, unsigned int source_id, int framerate); diff --git a/include/webrtc_source_private.h b/include/webrtc_source_private.h index f6031747..c06e0e0f 100644 --- a/include/webrtc_source_private.h +++ b/include/webrtc_source_private.h @@ -106,5 +106,7 @@ rtp_payload_info_s * _get_payload_info_by_encoding_name(const char *encoding_nam int _add_transceiver(webrtc_gst_slot_s *source, webrtc_media_type_e media_type, rtp_payload_info_s *payload_info); int _link_source_with_webrtcbin(webrtc_gst_slot_s *source, GstElement *webrtcbin); int _create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool need_capsfilter, GList **element_list, bool is_audio); +int _set_encoder_element_bitrate(GstElement *encoder, int target_bitrate); +int _get_encoder_element_bitrate(GstElement *encoder, int *target_bitrate); #endif /* __TIZEN_MEDIA_WEBRTC_SOURCE_COMMON_H__ */ diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index feda5900..7f2038eb 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.3.190 +Version: 0.3.191 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc.c b/src/webrtc.c index 82896909..04bfd9da 100644 --- a/src/webrtc.c +++ b/src/webrtc.c @@ -441,6 +441,30 @@ int webrtc_media_source_get_mute(webrtc_h webrtc, unsigned int source_id, webrtc _get_video_mute(_webrtc, source_id, muted); } +int webrtc_media_source_set_encoder_bitrate(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, int target_bitrate) +{ + g_autoptr(GMutexLocker) locker = NULL; + webrtc_s *_webrtc = (webrtc_s *)webrtc; + + RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + + locker = g_mutex_locker_new(&_webrtc->mutex); + + return _set_encoder_bitrate(webrtc, source_id, media_type, target_bitrate); +} + +int webrtc_media_source_get_encoder_bitrate(webrtc_h webrtc, unsigned int source_id, webrtc_media_type_e media_type, int *target_bitrate) +{ + g_autoptr(GMutexLocker) locker = NULL; + webrtc_s *_webrtc = (webrtc_s *)webrtc; + + RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + + locker = g_mutex_locker_new(&_webrtc->mutex); + + return _get_encoder_bitrate(webrtc, source_id, media_type, target_bitrate); +} + int webrtc_media_source_set_video_resolution(webrtc_h webrtc, unsigned int source_id, int width, int height) { g_autoptr(GMutexLocker) locker = NULL; diff --git a/src/webrtc_source.c b/src/webrtc_source.c index ac82a020..7dc34a19 100644 --- a/src/webrtc_source.c +++ b/src/webrtc_source.c @@ -1956,6 +1956,108 @@ int _get_audio_mute(webrtc_s *webrtc, unsigned int source_id, bool *muted) return WEBRTC_ERROR_NONE; } +static int __validate_source_for_encoder_bitrate(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, webrtc_gst_slot_s **source) +{ + webrtc_gst_slot_s *_source; + + RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + RET_VAL_IF(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0"); + RET_VAL_IF((_source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "could not find source"); + RET_VAL_IF(_source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE || _source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET || + _source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL, WEBRTC_ERROR_INVALID_PARAMETER, "invalid source type"); + + if (_source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE || + _source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET || + _source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL) { + LOG_ERROR("invalid type(%d)", _source->type); + return WEBRTC_ERROR_INVALID_PARAMETER; + } + + if (!(_source->media_types & + (media_type == WEBRTC_MEDIA_TYPE_AUDIO ? MEDIA_TYPE_AUDIO : MEDIA_TYPE_VIDEO))) { + LOG_ERROR("invalid media_type for source[media_types:0x%x, id:%u]", _source->media_types, source_id); + return WEBRTC_ERROR_INVALID_PARAMETER; + } + + if (source) + *source = _source; + + return WEBRTC_ERROR_NONE; +} + +int _set_encoder_bitrate(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, int target_bitrate) +{ + int ret; + int av_idx; + webrtc_gst_slot_s *source; + GstElement *encoder; + + RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + RET_VAL_IF(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0"); + RET_VAL_IF(target_bitrate <= 0, WEBRTC_ERROR_INVALID_PARAMETER, "target_bitrate <= 0"); + if ((ret = __validate_source_for_encoder_bitrate(webrtc, source_id, media_type, &source)) != WEBRTC_ERROR_NONE) + return ret; + + if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) { + av_idx = AV_IDX_AUDIO; + + } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) { + av_idx = AV_IDX_VIDEO; + + } else { + LOG_ERROR_IF_REACHED("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id); + return WEBRTC_ERROR_INVALID_PARAMETER; + } + + if ((encoder = gst_bin_get_by_name(source->bin, (av_idx == AV_IDX_AUDIO) ? ELEMENT_NAME_AUDIO_ENCODER : ELEMENT_NAME_VIDEO_ENCODER))) + if ((ret = _set_encoder_element_bitrate(encoder, target_bitrate)) != WEBRTC_ERROR_NONE) + return ret; + + source->av[av_idx].target_bitrate = target_bitrate; + + LOG_INFO("webrtc[%p] source_id[%u] media_type[%u] target_bitrate[%d]", webrtc, source_id, media_type, target_bitrate); + + return WEBRTC_ERROR_NONE; +} + +int _get_encoder_bitrate(webrtc_s *webrtc, unsigned int source_id, webrtc_media_type_e media_type, int *target_bitrate) +{ + int ret; + int av_idx; + webrtc_gst_slot_s *source; + GstElement *encoder; + int bitrate; + + RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + RET_VAL_IF(source_id == 0, WEBRTC_ERROR_INVALID_PARAMETER, "source_id is 0"); + RET_VAL_IF(target_bitrate == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "target_bitrate is NULL"); + if ((ret = __validate_source_for_encoder_bitrate(webrtc, source_id, media_type, &source)) != WEBRTC_ERROR_NONE) + return ret; + + if (media_type == WEBRTC_MEDIA_TYPE_AUDIO && source->media_types & MEDIA_TYPE_AUDIO) { + av_idx = AV_IDX_AUDIO; + + } else if (media_type == WEBRTC_MEDIA_TYPE_VIDEO && source->media_types & MEDIA_TYPE_VIDEO) { + av_idx = AV_IDX_VIDEO; + + } else { + LOG_ERROR_IF_REACHED("invalid media_type[%d] for source[media_types:0x%x, id:%u]", media_type, source->media_types, source_id); + return WEBRTC_ERROR_INVALID_PARAMETER; + } + + if ((encoder = gst_bin_get_by_name(source->bin, (av_idx == AV_IDX_AUDIO) ? ELEMENT_NAME_AUDIO_ENCODER : ELEMENT_NAME_VIDEO_ENCODER))) { + if ((ret = _get_encoder_element_bitrate(encoder, &bitrate)) != WEBRTC_ERROR_NONE) + return ret; + *target_bitrate = source->av[av_idx].target_bitrate = bitrate; + } else { + *target_bitrate = source->av[av_idx].target_bitrate; + } + + LOG_INFO("webrtc[%p] source_id[%u] media_type[%u] target_bitrate[%d]", webrtc, source_id, media_type, *target_bitrate); + + return WEBRTC_ERROR_NONE; +} + static int __build_loopback_audiosink(webrtc_gst_slot_s *source, GstElement *link_with) { webrtc_s *webrtc; diff --git a/src/webrtc_source_private.c b/src/webrtc_source_private.c index cb576d8e..6b50d3d7 100644 --- a/src/webrtc_source_private.c +++ b/src/webrtc_source_private.c @@ -899,6 +899,53 @@ static GstElement *__get_hw_encoder_element(webrtc_s *webrtc, webrtc_gst_slot_s } //LCOV_EXCL_STOP +static const char *__bitrate_properties[] = { + "bitrate", + "target-bitrate", + NULL, +}; + +int _set_encoder_element_bitrate(GstElement *encoder, int target_bitrate) +{ + int i; + + RET_VAL_IF(encoder == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "encoder is NULL"); + + for (i = 0; __bitrate_properties[i] != NULL; i++) { + if (!g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), __bitrate_properties[i])) + continue; + + g_object_set(G_OBJECT(encoder), __bitrate_properties[i], target_bitrate, NULL); + LOG_INFO("[%s] %s:%d", GST_OBJECT_NAME(gst_element_get_factory(encoder)), __bitrate_properties[i], target_bitrate); + return WEBRTC_ERROR_NONE; + } + + LOG_ERROR("unknown bitrate property name"); + return WEBRTC_ERROR_INVALID_OPERATION; +} + +int _get_encoder_element_bitrate(GstElement *encoder, int *target_bitrate) +{ + int i; + int bitrate; + + RET_VAL_IF(encoder == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "encoder is NULL"); + RET_VAL_IF(target_bitrate == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "target_bitrate is NULL"); + + for (i = 0; __bitrate_properties[i] != NULL; i++) { + if (!g_object_class_find_property(G_OBJECT_GET_CLASS(G_OBJECT(encoder)), __bitrate_properties[i])) + continue; + + g_object_get(G_OBJECT(encoder), __bitrate_properties[i], &bitrate, NULL); + LOG_INFO("[%s] %s:%d", GST_OBJECT_NAME(gst_element_get_factory(encoder)), __bitrate_properties[i], bitrate); + *target_bitrate = bitrate; + return WEBRTC_ERROR_NONE; + } + + LOG_ERROR("unknown bitrate property name"); + return WEBRTC_ERROR_INVALID_OPERATION; +} + static GstElement * __prepare_encoder(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool is_audio) { GstElement *encoder = NULL; @@ -952,6 +999,9 @@ static GstElement * __prepare_encoder(webrtc_s *webrtc, webrtc_gst_slot_s *sourc } } + if (source->av[is_audio ? AV_IDX_AUDIO : AV_IDX_VIDEO].target_bitrate > 0) + _set_encoder_element_bitrate(encoder, source->av[is_audio ? AV_IDX_AUDIO : AV_IDX_VIDEO].target_bitrate); + return encoder; }