]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7500 FS-7513: add video bandwidth control function and use it in mod_conference
authorAnthony Minessale <anthm@freeswitch.org>
Fri, 6 Feb 2015 22:13:32 +0000 (16:13 -0600)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:46:58 +0000 (12:46 -0500)
src/include/switch_core_media.h
src/include/switch_types.h
src/include/switch_utils.h
src/mod/applications/mod_conference/mod_conference.c
src/mod/codecs/mod_openh264/mod_openh264.cpp
src/mod/codecs/mod_vpx/mod_vpx.c
src/switch_core_media.c

index d213bb3b3d05254c5fa2b23f35849db8e789d73c..7f8e8868493c94d45c4239f27e74862e68ffa085 100644 (file)
@@ -307,6 +307,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_sess
 #define switch_core_media_gen_key_frame(_session) switch_core_media_codec_control(_session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_IO_WRITE, \
                                                                                                                                                                  SCC_VIDEO_REFRESH, SCCT_NONE, NULL, NULL, NULL) \
 
+#define switch_core_media_write_bandwidth(_session, _val) switch_core_media_codec_control(_session, SWITCH_MEDIA_TYPE_VIDEO, SWITCH_IO_WRITE, \
+                                                                                                                                                                                 SCC_VIDEO_BANDWIDTH, SCCT_STRING, _val, NULL, NULL) \
+
 
 SWITCH_DECLARE(switch_timer_t *) switch_core_media_get_timer(switch_core_session_t *session, switch_media_type_t mtype);
 SWITCH_DECLARE(void) switch_core_media_start_video_function(switch_core_session_t *session, switch_video_function_t video_function, void *user_data);
index b7b19195609e39cc21a48fb7300216fd1326e9f1..80f48096193b431bd0156122b4404bdb5263a8f8 100644 (file)
@@ -2192,11 +2192,14 @@ typedef switch_status_t (*switch_core_codec_video_encode_func_t) (switch_codec_t
 typedef switch_status_t (*switch_core_codec_video_decode_func_t) (switch_codec_t *codec, switch_frame_t *frame);
 
 typedef enum {
-       SCC_VIDEO_REFRESH = 0
+       SCC_VIDEO_REFRESH = 0,
+       SCC_VIDEO_BANDWIDTH
 } switch_codec_control_command_t;
 
 typedef enum {
-       SCCT_NONE = 0
+       SCCT_NONE = 0,
+       SCCT_STRING,
+       SCCT_INT,
 } switch_codec_control_type_t;
 
 typedef enum {
index 30b86ac34b21f28ed7a575e59ea03326a44c765c..4a35d23bf57e07c861dec9e713321a56f07c7ffe 100644 (file)
@@ -985,7 +985,9 @@ static inline uint32_t switch_parse_bandwidth_string(const char *bwv)
        if (bwv && (bw = (int32_t) atol(bwv))) {
                if (bw < 0) return 0;
 
-               if (switch_stristr("KB", bwv)) {
+               if (!strcasecmp(bwv, "auto")) {
+                       return -1;
+               } else if (switch_stristr("KB", bwv)) {
                        bw *= 8;
                } else if (switch_stristr("mb", bwv)) {
                        bw *= 1024;
index 3168c737ce8552d5b62fa9987abc1f633de2a022..af61eb9810cc60b9e9c5f786175db0fe8f681070 100644 (file)
@@ -428,7 +428,8 @@ typedef struct conference_obj {
        char *video_layout_name;
        char *video_layout_group;
        char *video_canvas_bgcolor;
-       uint32_t video_codec_bandwidth;
+       int32_t video_write_bandwidth;
+       switch_codec_settings_t video_codec_settings;
        uint32_t canvas_width;
        uint32_t canvas_height;
        uint32_t terminate_on_silence;
@@ -1368,7 +1369,8 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                                        if (imember->video_codec_index < 0) {
                                                write_codecs[i] = switch_core_alloc(conference->pool, sizeof(codec_set_t));
                                                
-                                               if (switch_core_codec_copy(check_codec, &write_codecs[i]->codec, conference->pool) == SWITCH_STATUS_SUCCESS) {
+                                               if (switch_core_codec_copy(check_codec, &write_codecs[i]->codec, 
+                                                                                                  &conference->video_codec_settings, conference->pool) == SWITCH_STATUS_SUCCESS) {
                                                        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,
                                                                                          "Setting up video write codec %s at slot %d\n", write_codecs[i]->codec.implementation->iananame, i);
 
@@ -1478,6 +1480,12 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
                                for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) {
                                        write_codecs[i]->frame.img = conference->canvas->img;
                                        write_canvas_image_to_codec_group(conference, write_codecs[i], i, timer.samplecount, need_refresh, need_keyframe);
+
+                                       if (conference->video_write_bandwidth) {
+                                               switch_core_codec_control(&write_codecs[i]->codec, SCC_VIDEO_BANDWIDTH, SCCT_INT, &conference->video_write_bandwidth, NULL, NULL);
+                                               conference->video_write_bandwidth = 0;
+                                       }
+
                                }
                        } else {
                                switch_mutex_lock(conference->member_mutex);
@@ -7616,6 +7624,24 @@ static switch_status_t conf_api_sub_volume_out(conference_member_t *member, swit
        return SWITCH_STATUS_SUCCESS;
 }
 
+static switch_status_t conf_api_sub_vid_bandwidth(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
+{
+       if (!switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) {
+               stream->write_function(stream, "Bandwidth control not available.\n");
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       if (!argv[2]) {
+               stream->write_function(stream, "Invalid input\n");
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       conference->video_write_bandwidth = switch_parse_bandwidth_string(argv[2]);
+       stream->write_function(stream, "Set Bandwidth %d\n", conference->video_write_bandwidth);
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 static switch_status_t conf_api_sub_vid_layout(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
 {
        video_layout_t *vlayout = NULL;
@@ -9282,7 +9308,8 @@ static api_command_t conf_api_sub_commands[] = {
        {"floor", (void_fn_t) & conf_api_sub_floor, CONF_API_SUB_MEMBER_TARGET, "floor", "<member_id|last>"},
        {"vid-floor", (void_fn_t) & conf_api_sub_vid_floor, CONF_API_SUB_MEMBER_TARGET, "vid-floor", "<member_id|last> [force]"},
        {"clear-vid-floor", (void_fn_t) & conf_api_sub_clear_vid_floor, CONF_API_SUB_ARGS_AS_ONE, "clear-vid-floor", ""},
-       {"vid-layout", (void_fn_t) & conf_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", "<layout name>"}
+       {"vid-layout", (void_fn_t) & conf_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", "<layout name>"},
+       {"vid-bandwidth", (void_fn_t) & conf_api_sub_vid_bandwidth, CONF_API_SUB_ARGS_SPLIT, "vid-bandwidth", "<BW>"}
 };
 
 #define CONFFUNCAPISIZE (sizeof(conf_api_sub_commands)/sizeof(conf_api_sub_commands[0]))
@@ -11364,7 +11391,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
        conference_parse_layouts(conference);
        
        if (video_codec_bandwidth) {
-               conference->video_codec_bandwidth = switch_parse_bandwidth_string(video_codec_bandwidth);
+               conference->video_codec_settings.video.bandwidth = switch_parse_bandwidth_string(video_codec_bandwidth);
        }
 
        if (video_layout_name) {
index 1de95aaae49d00acea790c35163c1d81e8c40bc9..565e7f1ff307f760debbc2b3df4ed4e68b56b910 100644 (file)
@@ -62,6 +62,7 @@ typedef struct h264_codec_context_s {
        int last_nalu_data_pos;
        int nalu_eat;
        int nalu_28_start;
+       int change_bandwidth;
        SSourcePicture pic;
 
        ISVCDecoder *decoder;
@@ -459,13 +460,14 @@ static switch_status_t init_encoder(h264_codec_context_t *context, uint32_t widt
 {
        int i;
 
-       context->encoder_params.iPicWidth = width;
-       context->encoder_params.iPicHeight = height;
+       if (width) context->encoder_params.iPicWidth = width;
+       if (height) context->encoder_params.iPicHeight = height;
        //context->encoder_params.iTargetBitrate = width * height * 8;
        for (int i=0; i<context->encoder_params.iSpatialLayerNum; i++) {
                context->encoder_params.sSpatialLayers[i].iVideoWidth = width;
                context->encoder_params.sSpatialLayers[i].iVideoHeight = height;
        }
+       FillSpecificParameters(context);
 
        /* just do it, the encoder will Uninitialize first by itself if already initialized */
        if (cmResultSuccess != context->encoder->InitializeExt(&context->encoder_params)) {
@@ -473,6 +475,10 @@ static switch_status_t init_encoder(h264_codec_context_t *context, uint32_t widt
                return SWITCH_STATUS_FALSE;
        }
 
+       switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Codec ready; picture size %dx%d Bandwidth: %d\n",
+                                         context->encoder_params.iPicWidth, context->encoder_params.iPicHeight, context->codec_settings.video.bandwidth);
+
+
        context->encoder_initialized = SWITCH_TRUE;
        return SWITCH_STATUS_SUCCESS;
 }
@@ -514,9 +520,17 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t
                init_encoder(context, width, height);
        }
 
+
+       if (context->change_bandwidth) {
+               context->codec_settings.video.bandwidth = context->change_bandwidth;
+               context->change_bandwidth = 0;
+               init_encoder(context, 0, 0);
+       }
+
        if (width != context->encoder_params.iPicWidth || height != context->encoder_params.iPicHeight ) {
-               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "picture size changed from %dx%d to %dx%d, reinitializing encoder",
+               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "picture size changed from %dx%d to %dx%d, reinitializing encoder\n",
                        context->encoder_params.iPicWidth, context->encoder_params.iPicHeight, width, height);
+
                init_encoder(context, width, height);
        }
 
@@ -683,6 +697,23 @@ static switch_status_t switch_h264_control(switch_codec_t *codec,
        case SCC_VIDEO_REFRESH:
                context->need_key_frame = 1;            
                break;
+       case SCC_VIDEO_BANDWIDTH:
+               {
+                       switch(ctype) {
+                       case SCCT_INT:
+                               context->change_bandwidth = *((int *) cmd_data);
+                               break;
+                       case SCCT_STRING:
+                               {
+                                       char *bwv = (char *) cmd_data;
+                                       context->change_bandwidth = switch_parse_bandwidth_string(bwv);
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+               break;
        default:
                break;
        }
index 287f6653d29bf42b1d20a3d725b5a5ef6212b9d4..d1cbbe47609a4d2482b5d2a04a4e9395c7deb0ca 100644 (file)
@@ -76,6 +76,7 @@ struct vpx_context {
        switch_size_t last_received_timestamp;
        switch_bool_t last_received_complete_picture;
        int need_key_frame;
+       int32_t change_bandwidth;
        uint64_t framecount;
        uint64_t framesum;
 };
@@ -97,6 +98,10 @@ static switch_status_t init_codec(switch_codec_t *codec)
                context->codec_settings.video.height = 720;
        }
 
+       if (context->codec_settings.video.bandwidth == -1) {
+               context->codec_settings.video.bandwidth = 0;
+       }
+
        if (context->codec_settings.video.bandwidth) {
                context->bandwidth = context->codec_settings.video.bandwidth;
        } else {
@@ -409,6 +414,13 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *
                init_codec(codec);
        }
 
+       if (context->change_bandwidth) {
+               context->codec_settings.video.bandwidth = context->change_bandwidth;
+               context->change_bandwidth = 0;
+               init_codec(codec);
+       }
+
+
        if (context->need_key_frame != 0) {
                // force generate a key frame
                switch_time_t now = switch_micro_time_now();
@@ -634,6 +646,23 @@ static switch_status_t switch_vpx_control(switch_codec_t *codec,
        case SCC_VIDEO_REFRESH:
                context->need_key_frame = 1;            
                break;
+       case SCC_VIDEO_BANDWIDTH:
+               {
+                       switch(ctype) {
+                       case SCCT_INT:
+                               context->change_bandwidth = *((int *) cmd_data);
+                               break;
+                       case SCCT_STRING:
+                               {
+                                       char *bwv = (char *) cmd_data;
+                                       context->change_bandwidth = switch_parse_bandwidth_string(bwv);
+                               }
+                               break;
+                       default:
+                               break;
+                       }
+               }
+               break;
        default:
                break;
        }
index ce10085cf4b924fd401c96045c450273215934db..4e2e1ed41682a2679f90a8ca7a7c3a0deccdb011 100644 (file)
@@ -9720,9 +9720,9 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_codec_control(switch_core_sess
                        }
 
                        smh->last_codec_refresh = now;
+                       switch_channel_set_flag(session->channel, CF_VIDEO_REFRESH_REQ);
                }
 
-               switch_channel_set_flag(session->channel, CF_VIDEO_REFRESH_REQ);
                return switch_core_codec_control(codec, cmd, ctype, cmd_data, rtype, ret_data);
        }