From: Hyunil Date: Thu, 2 Sep 2021 05:57:27 +0000 (+0900) Subject: Add new internal APIs for setting or unsetting crop screen source X-Git-Tag: submit/tizen/20210916.061019~2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=4c266f69da246a43accc1b92e48d09797940b05f;p=platform%2Fcore%2Fapi%2Fwebrtc.git Add new internal APIs for setting or unsetting crop screen source - webrtc_screen_source_set_crop() - webrtc_screen_source_unset_crop() - Add function test to webrtc_test [Version] 0.2.98 [Issue Type] New feature Change-Id: Ib1f36d6b84ce3ff429ff0ae20879b50b6f5af011 Signed-off-by: Hyunil --- diff --git a/include/webrtc_internal.h b/include/webrtc_internal.h index 60e78262..c5a70a2b 100644 --- a/include/webrtc_internal.h +++ b/include/webrtc_internal.h @@ -172,6 +172,53 @@ int webrtc_add_media_source_internal(webrtc_h webrtc, webrtc_media_source_type_i */ int webrtc_file_source_set_path(webrtc_h webrtc, unsigned int source_id, const char *path); +/** + * @internal + * @brief Sets the crop coordinates of screen source. + * @since_tizen 6.5 + * @remarks The base position is always the upper left conner of the UI coordinates.\n + * If the physical display is rotated and the UI is also rotated according to the rotation, @a portrait_mode and the cropping coordinates must be updated.\n + * The display resolution and video resolution of this screen source are different, + * this function uses the input parameters to crop the screen source based on the display resolution and it changes the video resolution of the screen source as a result. + * @param[in] webrtc WebRTC handle + * @param[in] source_id The file source id + * @param[in] x X coordinate of the upper left conner of the result area + * @param[in] y Y coordinate of the upper left conner of the result area + * @param[in] w Width of UI for cropping + * @param[in] h Height of UI for cropping + * @param[out] width Cropped video resolution width + * @param[out] height Cropped video resolution height + * @param[in] portrait_mode Screen is portrait mode or not (@c true = portrait mode, @c false = landscape mode) + * @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 + * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state + * @pre Add screen source to @a webrtc to get @a source_id by calling webrtc_add_media_source(). + * @pre @a webrtc state must be set to #WEBRTC_STATE_NEGOTIATING or #WEBRTC_STATE_PLAYING. + * @see webrtc_screen_source_unset_crop() + */ +int webrtc_screen_source_set_crop(webrtc_h webrtc, unsigned int source_id, int x, int y, int w, int h, bool portrait_mode, int *width, int *height); + +/** + * @internal + * @brief Unsets the crop coordinates of screen source. + * @since_tizen 6.5 + * @param[in] webrtc WebRTC handle + * @param[in] source_id The file source id + * @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 + * @retval #WEBRTC_ERROR_INVALID_STATE Invalid state + * @pre Add screen source to @a webrtc to get @a source_id by calling webrtc_add_media_source(). + * @pre @a webrtc state must be set to #WEBRTC_STATE_NEGOTIATING or #WEBRTC_STATE_PLAYING. + * @see webrtc_screen_source_set_crop() + */ +int webrtc_screen_source_unset_crop(webrtc_h webrtc, unsigned int source_id); + /** * @internal * @brief Creates a signaling server for private network. diff --git a/include/webrtc_private.h b/include/webrtc_private.h index d24dc757..6e7251d6 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -560,6 +560,8 @@ int _set_sound_stream_info(webrtc_s *webrtc, unsigned int source_id, sound_strea int _set_media_format(webrtc_s *webrtc, unsigned int source_id, media_format_h format); bool _check_if_format_is_set_to_packet_sources(webrtc_s *webrtc); int _set_media_path(webrtc_s *webrtc, unsigned int source_id, const char *path); +int _set_screen_source_crop(webrtc_s *webrtc, unsigned int source_id, int x, int y, int w, int h, bool portrait_mode, int *width, int *height); +int _unset_screen_source_crop(webrtc_s *webrtc, unsigned int source_id); bool _check_if_path_is_set_to_file_sources(webrtc_s *webrtc); int _push_media_packet(webrtc_s *webrtc, unsigned int source_id, media_packet_h packet); void _invoke_state_changed_cb(webrtc_s *webrtc, webrtc_state_e old, webrtc_state_e new); diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 9650774d..5ea9afef 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.97 +Version: 0.2.98 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc_internal.c b/src/webrtc_internal.c index 8ec24779..a2c7200a 100644 --- a/src/webrtc_internal.c +++ b/src/webrtc_internal.c @@ -92,4 +92,47 @@ int webrtc_file_source_set_path(webrtc_h webrtc, unsigned int source_id, const c RET_VAL_IF(_webrtc->state != WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, "the state should be IDLE"); return _set_media_path(_webrtc, source_id, path); -} \ No newline at end of file +} + +int webrtc_screen_source_set_crop(webrtc_h webrtc, unsigned int source_id, int x, int y, int w, int h, bool portrait_mode, int *width, int *height) +{ + int ret = WEBRTC_ERROR_NONE; + webrtc_gst_slot_s *source = NULL; + webrtc_s *_webrtc = (webrtc_s*)webrtc; + + RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + RET_VAL_IF(_webrtc->state == WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, "the state should not be IDLE"); + 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_SCREEN, WEBRTC_ERROR_INVALID_PARAMETER, "media source type is not screen"); + RET_VAL_IF(width == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "width is NULL"); + RET_VAL_IF(height == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "height is NULL"); + + g_mutex_lock(&_webrtc->mutex); + + ret = _set_screen_source_crop(_webrtc, source_id, x, y, w, h, portrait_mode, width, height); + + g_mutex_unlock(&_webrtc->mutex); + + return ret; +} + +int webrtc_screen_source_unset_crop(webrtc_h webrtc, unsigned int source_id) +{ + int ret = WEBRTC_ERROR_NONE; + webrtc_gst_slot_s *source = NULL; + webrtc_s *_webrtc = (webrtc_s*)webrtc; + + RET_VAL_IF(_webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); + RET_VAL_IF(_webrtc->state == WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_STATE, "the state should not be IDLE"); + 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_SCREEN, WEBRTC_ERROR_INVALID_PARAMETER, "media source type is not screen"); + + g_mutex_lock(&_webrtc->mutex); + + ret = _unset_screen_source_crop(_webrtc, source_id); + + g_mutex_unlock(&_webrtc->mutex); + + return ret; +} + diff --git a/src/webrtc_source.c b/src/webrtc_source.c index 4eb2ef0c..2ffd0bdc 100644 --- a/src/webrtc_source.c +++ b/src/webrtc_source.c @@ -37,6 +37,7 @@ #define DEFAULT_ELEMENT_QUEUE "queue" #define DEFAULT_ELEMENT_VOLUME "volume" #define DEFAULT_ELEMENT_INPUT_SELECTOR "input-selector" +#define DEFAULT_ELEMENT_VIDEOCROP "videocrop" #define ELEMENT_NAME_FIRST_CAPSFILTER "firstCapsfilter" #define ELEMENT_NAME_RTP_CAPSFILTER "rtpCapsfilter" @@ -52,6 +53,9 @@ #define DEFAULT_NAME_VIDEO_CAPSFILTER "videoCapsfilter" #define DEFAULT_NAME_AUDIO_PAYLOAD "audioPayload" #define DEFAULT_NAME_VIDEO_PAYLOAD "videoPayload" +#define DEFAULT_NAME_VIDEOCROP "videoCrop" +#define DEFAULT_NAME_SCREENSRC "waylandSrc" + #define APPEND_ELEMENT(x_list, x_element) \ do { \ @@ -815,6 +819,7 @@ static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source GstElement *payloader; GstElement *queue; GstElement *capsfilter2; + GstElement *videocrop; GstCaps *sink_caps; element_info_s elem_info; const gchar *encoder_klass_name; @@ -862,6 +867,12 @@ static int __create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source } } + if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_SCREEN && !source->zerocopy_enabled) { + if (!(videocrop = _create_element(DEFAULT_ELEMENT_VIDEOCROP, DEFAULT_NAME_VIDEOCROP))) + goto error; + APPEND_ELEMENT(*element_list, videocrop); + } + if (source->zerocopy_enabled) encoder = __get_hw_encoder_element(webrtc, source); else @@ -1236,7 +1247,7 @@ static int __build_screensrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) source->media_types = MEDIA_TYPE_VIDEO; source->zerocopy_enabled = __is_hw_encoder_used(webrtc, source->type, source->media_types); - if (!(screensrc = _create_element(__get_source_element(webrtc, WEBRTC_MEDIA_SOURCE_TYPE_SCREEN), ELEMENT_NAME_VIDEO_SRC))) + if (!(screensrc = _create_element(__get_source_element(webrtc, WEBRTC_MEDIA_SOURCE_TYPE_SCREEN), DEFAULT_NAME_SCREENSRC))) return WEBRTC_ERROR_INVALID_OPERATION; APPEND_ELEMENT(switch_src_list, screensrc); @@ -1253,9 +1264,11 @@ static int __build_screensrc(webrtc_s *webrtc, webrtc_gst_slot_s *source) goto exit; APPEND_ELEMENT(element_list, videoswitch); - if (!(videoconvert = _create_element(DEFAULT_ELEMENT_VIDEOCONVERT, NULL))) - goto exit; - APPEND_ELEMENT(element_list, videoconvert); + if (!source->zerocopy_enabled) { + if (!(videoconvert = _create_element(DEFAULT_ELEMENT_VIDEOCONVERT, NULL))) + goto exit; + APPEND_ELEMENT(element_list, videoconvert); + } if ((ret = __create_rest_of_elements(webrtc, source, true, &element_list)) != WEBRTC_ERROR_NONE) goto exit; @@ -3829,3 +3842,91 @@ int _get_display_visible_from_loopback(webrtc_s *webrtc, unsigned int track_id, return WEBRTC_ERROR_NONE; } + +int _set_screen_source_crop(webrtc_s *webrtc, unsigned int source_id, int x, int y, int w, int h, bool portrait_mode, int *width, int *height) +{ + webrtc_gst_slot_s *source = NULL; + GstElement *screen_source = NULL; + GstElement *videocrop = NULL; + int src_width, src_height, output_width, output_height; + int mirroring_x, mirroring_y, mirroring_width, mirroring_height; + float rw, rh; + int left, right, top, bottom; + + 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_SCREEN, WEBRTC_ERROR_INVALID_PARAMETER, "source type is not screen"); + RET_VAL_IF(w == 0, WEBRTC_ERROR_INVALID_PARAMETER, "w is 0"); + RET_VAL_IF(h == 0, WEBRTC_ERROR_INVALID_PARAMETER, "h is 0"); + RET_VAL_IF(width == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "width is NULL"); + RET_VAL_IF(height == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "height is NULL"); + + screen_source = gst_bin_get_by_name(source->bin, DEFAULT_NAME_SCREENSRC); + RET_VAL_IF(screen_source == NULL, WEBRTC_ERROR_INVALID_OPERATION, "sreen_source is NULL"); + + videocrop = gst_bin_get_by_name(source->bin, DEFAULT_NAME_VIDEOCROP); + RET_VAL_IF(videocrop == NULL, WEBRTC_ERROR_INVALID_OPERATION, "videocrop is NULL"); + + LOG_INFO("set source crop x:%d, y:%d, width:%d, height:%d, mode:%s", x, y, w, h, (portrait_mode) ? "portrait" : "landscape"); + + g_object_get(G_OBJECT(screen_source), + portrait_mode ? "mirroring-v-src-width" : "mirroring-h-src-width", &src_width, + portrait_mode ? "mirroring-v-src-height" : "mirroring-h-src-height", &src_height, + portrait_mode ? "mirroring-v-x" : "mirroring-h-x", &mirroring_x, + portrait_mode ? "mirroring-v-y" : "mirroring-h-y", &mirroring_y, + portrait_mode ? "mirroring-v-width" : "mirroring-h-width", &mirroring_width, + portrait_mode ? "mirroring-v-height" : "mirroring-h-height", &mirroring_height, + "output-width", &output_width, + "output-height", &output_height, + NULL); + + rw = (float)src_width / mirroring_width; + rh = (float)src_height / mirroring_height; + left = mirroring_x + ((float)x / rw); + right = output_width - (left + (float)w / rw); + top = mirroring_y + ((float)y /rh); + bottom = output_height - (top + (float)h / rh); + + LOG_INFO("Screen source info: source[width:%d, height:%d], output[width:%d, height:%d]" + "mirroring[x:%d y:%d width:%d, height:%d", src_width, src_height, output_width, + output_height, mirroring_x, mirroring_y, mirroring_width, mirroring_height); + + g_object_set(G_OBJECT(videocrop), "left", left, "right", right, "top", top, + "bottom", bottom, NULL); + + LOG_INFO("cropped: left:%d, right:%d, top:%d, bottom:%d", left, right, top, bottom); + + *width = output_width - (left + right); + *height = output_height - (top + bottom); + LOG_INFO("source_id[%u], video resolution is changed [%dx%d] ==> [%dx%d]", source_id, + output_width, output_height, *width, *height); + + return WEBRTC_ERROR_NONE; +} + +int _unset_screen_source_crop(webrtc_s *webrtc, unsigned int source_id) +{ + webrtc_gst_slot_s *source = NULL; + GstElement *videocrop = NULL; + GstElement *screen_source = NULL; + int left, right, top, bottom; + + 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_SCREEN, WEBRTC_ERROR_INVALID_PARAMETER, "source type is not screen"); + + screen_source = gst_bin_get_by_name(source->bin, DEFAULT_NAME_SCREENSRC); + RET_VAL_IF(screen_source == NULL, WEBRTC_ERROR_INVALID_OPERATION, "sreen_source is NULL"); + + videocrop = gst_bin_get_by_name(source->bin, DEFAULT_NAME_VIDEOCROP); + RET_VAL_IF(videocrop == NULL, WEBRTC_ERROR_INVALID_OPERATION, "videocrop is NULL"); + + g_object_get(G_OBJECT(videocrop), "left", &left, "right", &right, "top", &top, "bottom", &bottom, NULL); + RET_VAL_IF(left == 0 && right == 0 && top == 0 && bottom == 0, WEBRTC_ERROR_INVALID_OPERATION, "webrtc_screen_source_set_crop was not set"); + + g_object_set(G_OBJECT(videocrop), "left", 0, "right", 0, "top", 0, "bottom", 0, NULL); + + return WEBRTC_ERROR_NONE; +} diff --git a/test/webrtc_test.c b/test/webrtc_test.c index 6cce4113..0fc4867b 100644 --- a/test/webrtc_test.c +++ b/test/webrtc_test.c @@ -98,6 +98,8 @@ enum { CURRENT_STATUS_CREATE_PRIVATE_SIGNALING_SERVER, CURRENT_STATUS_CONNECT_TO_PRIVATE_SIGNALING_SERVER, CURRENT_STATUS_MUTE_MEDIA_SOURCE, + CURRENT_STATUS_SET_CROP_SCREEN_SOURCE, + CURRENT_STATUS_UNSET_CROP_SCREEN_SOURCE, CURRENT_STATUS_TERMINATE, }; @@ -1071,6 +1073,26 @@ static void _webrtc_media_source_set_mute(int index, unsigned int source_id, web g_print("webrtc_media_source_get_mute() success, source_id[%d], mute_status[%d]\n", source_id, mute_status); } +static void _webrtc_screen_source_set_crop(int index, unsigned int source_id, int x, int y, int w, int h, int is_vertical, int *width, int *height) +{ + int ret = WEBRTC_ERROR_NONE; + + ret = webrtc_screen_source_set_crop(g_conns[index].webrtc, source_id, x, y, w, h, is_vertical, width, height); + if (ret != WEBRTC_ERROR_NONE) + g_print("failed to webrtc_screen_source_set_crop(), source_id[%d], ret[0x%x]\n", source_id, ret); + + g_print("cropped video resolution[%dx%d]\n", *width, *height); +} + +static void _webrtc_screen_source_unset_crop(int index, unsigned int source_id) +{ + int ret = WEBRTC_ERROR_NONE; + + ret = webrtc_screen_source_unset_crop(g_conns[index].webrtc, source_id); + if (ret != WEBRTC_ERROR_NONE) + g_print("failed to webrtc_screen_source_unset_crop(), source_id[%d], ret[0x%x]\n", source_id, ret); +} + static void __offer_created_cb(webrtc_h webrtc, const char *description, void *user_data) { connection_s *conn = (connection_s *)user_data; @@ -3728,6 +3750,12 @@ void _interpret_main_menu(char *cmd) } else if (strncmp(cmd, "scd", 3) == 0) { _webrtc_signaling_disconnect(g_conn_index); + } else if (strncmp(cmd, "scs", 3) == 0) { + g_conns[g_conn_index].menu_state = CURRENT_STATUS_SET_CROP_SCREEN_SOURCE; + + } else if (strncmp(cmd, "ucs", 3) == 0) { + g_conns[g_conn_index].menu_state = CURRENT_STATUS_UNSET_CROP_SCREEN_SOURCE; + } else { g_print("unknown menu \n"); } @@ -3819,6 +3847,8 @@ void display_sub_basic() g_print("gv. Get display visible\n"); g_print("al. Set audio loopback\t"); g_print("vl. Set video loopback\n"); + g_print("scs. Set crop screen source\n"); + g_print("ucs. Unset crop screen source\n"); g_print("------------------------------------- Data Channel --------------------------------------\n"); g_print("cd. Create data channel\t"); g_print("dd. Destroy data channel\n"); @@ -3990,6 +4020,24 @@ static void displaymenu() else if (g_conns[g_conn_index].cnt == 2) g_print("*** input mute mode.(0:unmuted 1:muted)\n"); + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SET_CROP_SCREEN_SOURCE) { + if (g_conns[g_conn_index].cnt == 0) + g_print("*** input source id.\n"); + else if (g_conns[g_conn_index].cnt == 1) + g_print("*** input x.\n"); + else if (g_conns[g_conn_index].cnt == 2) + g_print("*** input y.\n"); + else if (g_conns[g_conn_index].cnt == 3) + g_print("*** input width.\n"); + else if (g_conns[g_conn_index].cnt == 4) + g_print("*** input height.\n"); + else if (g_conns[g_conn_index].cnt == 5) + g_print("*** input whether screen rotates (0: horizontal, 1: vertical).\n"); + + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_UNSET_CROP_SCREEN_SOURCE) { + if (g_conns[g_conn_index].cnt == 0) + g_print("*** input source id.\n"); + } else if (g_conns[g_conn_index].menu_state == CURRENT_STATUS_SET_STUN_SERVER) { g_print("*** input STUN server address.\n"); @@ -4467,6 +4515,53 @@ static void interpret(char *cmd) } break; } + case CURRENT_STATUS_SET_CROP_SCREEN_SOURCE: { + static unsigned int id; + static int x; + static int y; + static int w; + static int h; + static int is_vertical; + value = atoi(cmd); + + switch (g_conns[g_conn_index].cnt) { + case 0: + id = value; + g_conns[g_conn_index].cnt++; + break; + case 1: + x = value; + g_conns[g_conn_index].cnt++; + break; + case 2: + y = value; + g_conns[g_conn_index].cnt++; + break; + case 3: + w = value; + g_conns[g_conn_index].cnt++; + break; + case 4: + h = value; + g_conns[g_conn_index].cnt++; + break; + case 5: + is_vertical = value; + int width, height; + _webrtc_screen_source_set_crop(g_conn_index, id, x, y, w, h, is_vertical, &width, &height); + x = y = w = h = is_vertical = 0; + g_conns[g_conn_index].cnt = 0; + reset_menu_state(); + break; + } + break; + } + case CURRENT_STATUS_UNSET_CROP_SCREEN_SOURCE: { + value = atoi(cmd); + _webrtc_screen_source_unset_crop(g_conn_index, value); + reset_menu_state(); + break; + } case CURRENT_STATUS_MUTE_MEDIA_SOURCE: { static unsigned int id; static unsigned int media_type;