From fcf32fd53d7c57ff27b212166af2ba5a771e08d6 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Fri, 6 Feb 2015 16:13:32 -0600 Subject: [PATCH] FS-7500 FS-7513: add video bandwidth control function and use it in mod_conference --- src/include/switch_core_media.h | 3 ++ src/include/switch_types.h | 7 +++- src/include/switch_utils.h | 4 +- .../mod_conference/mod_conference.c | 35 ++++++++++++++++-- src/mod/codecs/mod_openh264/mod_openh264.cpp | 37 +++++++++++++++++-- src/mod/codecs/mod_vpx/mod_vpx.c | 29 +++++++++++++++ src/switch_core_media.c | 2 +- 7 files changed, 106 insertions(+), 11 deletions(-) diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index d213bb3b3d..7f8e886849 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -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); diff --git a/src/include/switch_types.h b/src/include/switch_types.h index b7b1919560..80f4809619 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -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 { diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 30b86ac34b..4a35d23bf5 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -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; diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 3168c737ce..af61eb9810 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -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", ""}, {"vid-floor", (void_fn_t) & conf_api_sub_vid_floor, CONF_API_SUB_MEMBER_TARGET, "vid-floor", " [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", ""} + {"vid-layout", (void_fn_t) & conf_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", ""}, + {"vid-bandwidth", (void_fn_t) & conf_api_sub_vid_bandwidth, CONF_API_SUB_ARGS_SPLIT, "vid-bandwidth", ""} }; #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) { diff --git a/src/mod/codecs/mod_openh264/mod_openh264.cpp b/src/mod/codecs/mod_openh264/mod_openh264.cpp index 1de95aaae4..565e7f1ff3 100644 --- a/src/mod/codecs/mod_openh264/mod_openh264.cpp +++ b/src/mod/codecs/mod_openh264/mod_openh264.cpp @@ -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; iencoder_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; } diff --git a/src/mod/codecs/mod_vpx/mod_vpx.c b/src/mod/codecs/mod_vpx/mod_vpx.c index 287f6653d2..d1cbbe4760 100644 --- a/src/mod/codecs/mod_vpx/mod_vpx.c +++ b/src/mod/codecs/mod_vpx/mod_vpx.c @@ -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; } diff --git a/src/switch_core_media.c b/src/switch_core_media.c index ce10085cf4..4e2e1ed416 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -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); }