From: hj kim Date: Wed, 21 Sep 2022 02:28:28 +0000 (+0900) Subject: add videorate to support dynamic framerate change X-Git-Tag: accepted/tizen/unified/20220927.132346~3 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F99%2F281699%2F10;p=platform%2Fcore%2Fapi%2Fwebrtc.git add videorate to support dynamic framerate change It doesn't support increasing framerate. [Version] 0.3.246 [Issue Type] Improvement Change-Id: Iea5ce0881ae55e1d881d847b88ff41dcede75a6f --- diff --git a/include/webrtc_private.h b/include/webrtc_private.h index 8d7b1d86..51c4fd6a 100644 --- a/include/webrtc_private.h +++ b/include/webrtc_private.h @@ -568,6 +568,7 @@ typedef struct _webrtc_gst_slot_s { int origin_height; int width; int height; + int origin_framerate; int framerate; } video_info; struct { @@ -716,6 +717,7 @@ void _remove_probe_from_pad_for_render(webrtc_gst_slot_s *source, unsigned int i void _set_caps_for_render(webrtc_gst_slot_s *source, GstCaps *caps, int av_idx); void _unset_caps_for_render(webrtc_gst_slot_s *source, int av_idx); int _update_caps_for_render_with_resolution(webrtc_gst_slot_s *source, int width, int height); +int _update_caps_for_render_with_framerate(webrtc_gst_slot_s *source, int framerate); void _set_need_decoding_for_loopback(webrtc_gst_slot_s *source, int av_idx, bool need_decoding); void _destroy_looopback_render_pipeline(webrtc_gst_slot_s *source, int av_idx); diff --git a/include/webrtc_source_private.h b/include/webrtc_source_private.h index 95ae4abd..27eca6d2 100644 --- a/include/webrtc_source_private.h +++ b/include/webrtc_source_private.h @@ -40,6 +40,7 @@ #define DEFAULT_ELEMENT_INPUT_SELECTOR "input-selector" #define DEFAULT_ELEMENT_VIDEOCROP "videocrop" #define DEFAULT_ELEMENT_VIDEOSCALE "videoscale" +#define DEFAULT_ELEMENT_VIDEORATE "videorate" #define DEFAULT_ELEMENT_FILESRC "filesrc" #define ELEMENT_NAME_FIRST_CAPSFILTER "firstCapsfilter" @@ -64,6 +65,7 @@ #define ELEMENT_NAME_AUDIO_APPSRC "audioAppsrc" #define ELEMENT_NAME_VIDEO_APPSRC "videoAppsrc" #define ELEMENT_NAME_VIDEOSCALE_CAPSFILTER "videoscaleCapsfilter" +#define ELEMENT_NAME_VIDEORATE_CAPSFILTER "videorateCapsfilter" typedef enum { ELEMENT_APPSRC, diff --git a/packaging/capi-media-webrtc.spec b/packaging/capi-media-webrtc.spec index 1f142c42..4860534f 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.245 +Version: 0.3.246 Release: 0 Group: Multimedia/API License: Apache-2.0 diff --git a/src/webrtc_source.c b/src/webrtc_source.c index d6903b38..ef0374ac 100644 --- a/src/webrtc_source.c +++ b/src/webrtc_source.c @@ -26,33 +26,6 @@ static GstPadProbeReturn __camerasrc_probe_cb(GstPad *pad, GstPadProbeInfo *info, gpointer u_data); -static GstCaps *__make_video_raw_caps_with_framerate(webrtc_gst_slot_s *source, webrtc_ini_s *ini, int framerate) -{ - GstCaps *caps = NULL; - - RET_VAL_IF(source == NULL, NULL, "source is NULL"); - RET_VAL_IF(ini == NULL, NULL, "ini is NULL"); - - switch (source->type) { - case WEBRTC_MEDIA_SOURCE_TYPE_CAMERA: - case WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST: - case WEBRTC_MEDIA_SOURCE_TYPE_SCREEN: { - caps = gst_caps_new_simple(MEDIA_TYPE_VIDEO_RAW, - "format", G_TYPE_STRING, _get_raw_format_from_ini(ini, source->type, MEDIA_TYPE_VIDEO), - "framerate", GST_TYPE_FRACTION, framerate, 1, - "width", G_TYPE_INT, source->video_info.width, - "height", G_TYPE_INT, source->video_info.height, - NULL); - break; - } - default: - LOG_ERROR_IF_REACHED("type(%d)", source->type); - break; - } - - return caps; -} - //LCOV_EXCL_START static bool __link_switch_srcs(GstElement *switch_element, GList *switch_src_list) { @@ -79,7 +52,9 @@ static bool __set_default_video_info(webrtc_gst_slot_s *source, const ini_item_m RET_VAL_IF(source == NULL, false, "source is NULL"); RET_VAL_IF(ini_source == NULL, false, "ini_source is NULL"); + source->video_info.origin_framerate = ini_source->v_framerate; source->video_info.framerate = ini_source->v_framerate; + source->video_info.origin_width = ini_source->v_width; source->video_info.origin_height = ini_source->v_height; _set_video_src_resolution(source, ini_source->v_width, ini_source->v_height); @@ -962,6 +937,7 @@ int _set_video_resolution(webrtc_s *webrtc, unsigned int source_id, int width, i webrtc_gst_slot_s *source; GstElement *capsfilter; bool drc_support; + GstCaps *new_caps = NULL; RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "could not find source"); @@ -984,6 +960,10 @@ int _set_video_resolution(webrtc_s *webrtc, unsigned int source_id, int width, i if (webrtc->state == WEBRTC_STATE_IDLE || drc_support) { capsfilter = _find_element_in_bin(source->bin, ELEMENT_NAME_FIRST_CAPSFILTER); + if (capsfilter) + if (!(new_caps = _make_video_raw_caps_with_resolution(source, &webrtc->ini, width, height))) + return WEBRTC_ERROR_INVALID_OPERATION; + source->video_info.origin_width = width; source->video_info.origin_height = height; } else { @@ -1001,13 +981,14 @@ int _set_video_resolution(webrtc_s *webrtc, unsigned int source_id, int width, i capsfilter = _find_element_in_bin(source->bin, ELEMENT_NAME_VIDEOSCALE_CAPSFILTER); RET_VAL_IF(!capsfilter, WEBRTC_ERROR_INVALID_OPERATION, "not supported dynamic resolution change"); - } - if (capsfilter) { - GstCaps *new_caps; + new_caps = gst_caps_new_simple(MEDIA_TYPE_VIDEO_RAW, + "width", G_TYPE_INT, width, + "height", G_TYPE_INT, height, + NULL); + } - if (!(new_caps = _make_video_raw_caps_with_resolution(source, &webrtc->ini, width, height))) - return WEBRTC_ERROR_INVALID_OPERATION; + if (capsfilter && new_caps) { PRINT_CAPS(new_caps, "capsfilter"); g_object_set(G_OBJECT(capsfilter), "caps", new_caps, NULL); @@ -1049,9 +1030,9 @@ int _get_video_resolution(webrtc_s *webrtc, unsigned int source_id, int *width, int _set_video_framerate(webrtc_s *webrtc, unsigned int source_id, int framerate) { + int ret; webrtc_gst_slot_s *source; GstElement *capsfilter; - GstCaps *new_caps = NULL; RET_VAL_IF(webrtc == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "webrtc is NULL"); RET_VAL_IF((source = _get_slot_by_id(webrtc->gst.source_slots, source_id)) == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "could not find source"); @@ -1060,20 +1041,29 @@ int _set_video_framerate(webrtc_s *webrtc, unsigned int source_id, int framerate RET_VAL_IF((source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the media packet source"); RET_VAL_IF((source->type == WEBRTC_MEDIA_SOURCE_TYPE_NULL), WEBRTC_ERROR_INVALID_PARAMETER, "this API does not support the null source"); - /* TODO: framerate reconfiguration implementation, until then it will return error. */ - RET_VAL_IF(webrtc->state != WEBRTC_STATE_IDLE, WEBRTC_ERROR_INVALID_OPERATION, "for now, it is only supported in IDLE state"); + if (webrtc->state == WEBRTC_STATE_IDLE) { + source->video_info.origin_framerate = framerate; + source->video_info.framerate = framerate; - /* FIXME: check if the framerate is supported or not */ - if ((capsfilter = _find_element_in_bin(source->bin, ELEMENT_NAME_FIRST_CAPSFILTER))) { - if (!(new_caps = __make_video_raw_caps_with_framerate(source, &webrtc->ini, framerate))) - return WEBRTC_ERROR_INVALID_OPERATION; - PRINT_CAPS(new_caps, "capsfilter"); + return WEBRTC_ERROR_NONE; + } + + RET_VAL_IF(framerate > source->video_info.origin_framerate, WEBRTC_ERROR_INVALID_OPERATION, + "it doesn't support increasing framerate. origin [%d] requested [%d]", source->video_info.origin_framerate, framerate); + + if ((capsfilter = _find_element_in_bin(source->bin, ELEMENT_NAME_VIDEORATE_CAPSFILTER))) { + GstCaps *new_caps = gst_caps_new_simple(MEDIA_TYPE_VIDEO_RAW, + "framerate", GST_TYPE_FRACTION, framerate, 1, + NULL); + PRINT_CAPS(new_caps, ELEMENT_NAME_VIDEORATE_CAPSFILTER); g_object_set(G_OBJECT(capsfilter), "caps", new_caps, NULL); gst_caps_unref(new_caps); - } + ret = _update_caps_for_render_with_framerate(source, framerate); + RET_VAL_IF(ret != WEBRTC_ERROR_NONE, ret, "failed to _update_caps_for_render_with_framerate()"); + source->video_info.framerate = framerate; LOG_INFO("webrtc[%p], source_id[%u], framerate[%d]", webrtc, source_id, framerate); diff --git a/src/webrtc_source_loopback.c b/src/webrtc_source_loopback.c index 3699737a..7dc6b75b 100644 --- a/src/webrtc_source_loopback.c +++ b/src/webrtc_source_loopback.c @@ -666,6 +666,49 @@ int _update_caps_for_render_with_resolution(webrtc_gst_slot_s *source, int width return WEBRTC_ERROR_NONE; } +static GstCaps *__make_video_raw_caps_with_framerate(webrtc_gst_slot_s *source, webrtc_ini_s *ini, int framerate) +{ + GstCaps *caps = NULL; + + RET_VAL_IF(source == NULL, NULL, "source is NULL"); + RET_VAL_IF(ini == NULL, NULL, "ini is NULL"); + + switch (source->type) { + case WEBRTC_MEDIA_SOURCE_TYPE_CAMERA: + case WEBRTC_MEDIA_SOURCE_TYPE_VIDEOTEST: + case WEBRTC_MEDIA_SOURCE_TYPE_SCREEN: { + caps = gst_caps_new_simple(MEDIA_TYPE_VIDEO_RAW, + "format", G_TYPE_STRING, _get_raw_format_from_ini(ini, source->type, MEDIA_TYPE_VIDEO), + "framerate", GST_TYPE_FRACTION, framerate, 1, + "width", G_TYPE_INT, source->video_info.width, + "height", G_TYPE_INT, source->video_info.height, + NULL); + break; + } + default: + LOG_ERROR_IF_REACHED("type(%d)", source->type); + break; + } + + return caps; +} + +int _update_caps_for_render_with_framerate(webrtc_gst_slot_s *source, int framerate) +{ + GstCaps *new_caps; + + RET_VAL_IF(source == NULL, WEBRTC_ERROR_INVALID_PARAMETER, "source is NULL"); + + if (!(new_caps = __make_video_raw_caps_with_framerate(source, &source->webrtc->ini, framerate))) + return WEBRTC_ERROR_INVALID_OPERATION; + PRINT_CAPS(new_caps, "appsrc"); + + _unset_caps_for_render(source, AV_IDX_VIDEO); + _set_caps_for_render(source, new_caps, AV_IDX_VIDEO); + + return WEBRTC_ERROR_NONE; +} + void _set_need_decoding_for_loopback(webrtc_gst_slot_s *source, int av_idx, bool need_decoding) { RET_IF(source == NULL, "source is NULL"); diff --git a/src/webrtc_source_private.c b/src/webrtc_source_private.c index b2535dc0..b892a942 100644 --- a/src/webrtc_source_private.c +++ b/src/webrtc_source_private.c @@ -668,6 +668,9 @@ static bool __is_videoscale_needed(webrtc_s *webrtc, webrtc_gst_slot_s *source) if (!(source->media_types & MEDIA_TYPE_VIDEO)) return false; + if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE || source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) + return false; + _get_video_encoded_support_from_ini(&webrtc->ini, source->type, &encoded_support); if (encoded_support) return false; @@ -677,9 +680,26 @@ static bool __is_videoscale_needed(webrtc_s *webrtc, webrtc_gst_slot_s *source) if (drc_support) return false; + return true; +} + +static bool __is_videorate_needed(webrtc_s *webrtc, webrtc_gst_slot_s *source) +{ + bool encoded_support; + + RET_VAL_IF(webrtc == NULL, false, "webrtc is NULL"); + RET_VAL_IF(source == NULL, false, "source is NULL"); + + if (!(source->media_types & MEDIA_TYPE_VIDEO)) + return false; + if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_FILE || source->type == WEBRTC_MEDIA_SOURCE_TYPE_MEDIA_PACKET) return false; + _get_video_encoded_support_from_ini(&webrtc->ini, source->type, &encoded_support); + if (encoded_support) + return false; + return true; } @@ -748,31 +768,48 @@ int _create_rest_of_elements(webrtc_s *webrtc, webrtc_gst_slot_s *source, bool n goto error; APPEND_ELEMENT(*element_list, videoscaleCapsfilter); - if ((caps = __make_default_raw_caps(source, &webrtc->ini))) { - PRINT_CAPS(caps, ELEMENT_NAME_VIDEOSCALE_CAPSFILTER); - g_object_set(G_OBJECT(videoscaleCapsfilter), "caps", caps, NULL); + caps = gst_caps_new_simple(MEDIA_TYPE_VIDEO_RAW, + "width", G_TYPE_INT, source->video_info.width, + "height", G_TYPE_INT, source->video_info.height, + NULL); - gst_caps_unref(caps_for_render); - caps_for_render = caps; - } + PRINT_CAPS(caps, ELEMENT_NAME_VIDEOSCALE_CAPSFILTER); + g_object_set(G_OBJECT(videoscaleCapsfilter), "caps", caps, NULL); + gst_caps_unref(caps); gst_object_unref(pad_for_render); pad_for_render = gst_element_get_static_pad(videoscaleCapsfilter, "src"); } - if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_SCREEN && !source->zerocopy_enabled) { + if (__is_videorate_needed(webrtc, source)) { + GstElement *videorate; + GstElement *videorateCapsfilter; GstCaps *caps; - if (!(videocrop = _create_element(DEFAULT_ELEMENT_VIDEOCROP, ELEMENT_NAME_VIDEOCROP))) + if (!(videorate = _create_element(DEFAULT_ELEMENT_VIDEORATE, NULL))) goto error; - APPEND_ELEMENT(*element_list, videocrop); + APPEND_ELEMENT(*element_list, videorate); - if ((caps = __make_default_raw_caps(source, &webrtc->ini))) { - PRINT_CAPS(caps, ELEMENT_NAME_VIDEOSCALE_CAPSFILTER); + if (!(videorateCapsfilter = _create_element(DEFAULT_ELEMENT_CAPSFILTER, ELEMENT_NAME_VIDEORATE_CAPSFILTER))) + goto error; + APPEND_ELEMENT(*element_list, videorateCapsfilter); - gst_caps_unref(caps_for_render); - caps_for_render = caps; - } + caps = gst_caps_new_simple(MEDIA_TYPE_VIDEO_RAW, + "framerate", GST_TYPE_FRACTION, source->video_info.framerate, 1, + NULL); + + PRINT_CAPS(caps, ELEMENT_NAME_VIDEORATE_CAPSFILTER); + g_object_set(G_OBJECT(videorateCapsfilter), "caps", caps, NULL); + gst_caps_unref(caps); + + gst_object_unref(pad_for_render); + pad_for_render = gst_element_get_static_pad(videorateCapsfilter, "src"); + } + + if (source->type == WEBRTC_MEDIA_SOURCE_TYPE_SCREEN && !source->zerocopy_enabled) { + if (!(videocrop = _create_element(DEFAULT_ELEMENT_VIDEOCROP, ELEMENT_NAME_VIDEOCROP))) + goto error; + APPEND_ELEMENT(*element_list, videocrop); gst_object_unref(pad_for_render); pad_for_render = gst_element_get_static_pad(videocrop, "src");