add videorate to support dynamic framerate change 99/281699/10
authorhj kim <backto.kim@samsung.com>
Wed, 21 Sep 2022 02:28:28 +0000 (11:28 +0900)
committerhj kim <backto.kim@samsung.com>
Fri, 23 Sep 2022 05:22:12 +0000 (14:22 +0900)
It doesn't support increasing framerate.

[Version] 0.3.246
[Issue Type] Improvement

Change-Id: Iea5ce0881ae55e1d881d847b88ff41dcede75a6f

include/webrtc_private.h
include/webrtc_source_private.h
packaging/capi-media-webrtc.spec
src/webrtc_source.c
src/webrtc_source_loopback.c
src/webrtc_source_private.c

index 8d7b1d861882b68c36eed453de82f5c0a320300f..51c4fd6ac50e551df1c354014f744f9445003206 100644 (file)
@@ -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);
 
index 95ae4abd57316b6e48257eb313871ce7f995f95a..27eca6d2d906362f6b63b4a4ec97666d2f4ff058 100644 (file)
@@ -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,
index 1f142c420b50665c11c03bd82bc712b5b4960ea1..4860534f2b4a2389fe630f205b51a7612f5bcb80 100644 (file)
@@ -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
index d6903b386c4f4635343845d1458dd73f5566f2d9..ef0374acdc7e161995477abf6854661753c84315 100644 (file)
 
 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);
index 3699737a6263c9cd3919a47a4bb39f901541c3c5..7dc6b75b311aa7dd2110a962cbc775f98a0f2a3a 100644 (file)
@@ -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");
index b2535dc0e7588fa1f674daf99bf4a3ff0fc1e47d..b892a942760e0cd521a9798c91655df475cc4d55 100644 (file)
@@ -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");