diff --git a/conf/vanilla/autoload_configs/conference.conf.xml b/conf/vanilla/autoload_configs/conference.conf.xml index 3b3342b1e6..0f90510736 100644 --- a/conf/vanilla/autoload_configs/conference.conf.xml +++ b/conf/vanilla/autoload_configs/conference.conf.xml @@ -183,6 +183,7 @@ + diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 068e5d0849..4520ca23c6 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -2193,7 +2193,8 @@ typedef switch_status_t (*switch_core_codec_video_decode_func_t) (switch_codec_t typedef enum { SCC_VIDEO_REFRESH = 0, - SCC_VIDEO_BANDWIDTH + SCC_VIDEO_BANDWIDTH, + SCC_VIDEO_RESET } switch_codec_control_command_t; typedef enum { diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 9533025d58..8f01435827 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -55,6 +55,27 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_conference_load); SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_conference_shutdown); SWITCH_MODULE_DEFINITION(mod_conference, mod_conference_load, mod_conference_shutdown, NULL); +struct conf_fps { + float fps; + int ms; + int samples; +}; + +static struct conf_fps FPS_VALS[] = { + {1.0f, 1000, 90}, + {5.0f, 200, 450}, + {10.0f, 100, 900}, + {15.0f, 66, 1364}, + {16.60f, 60, 1500}, + {25.0f, 40, 2250}, + {30.0f, 33, 2700}, + {33.0f, 30, 2790}, + {66.60f, 15, 6000}, + {100.0f, 10, 9000}, + {0,0,0} +}; + + typedef enum { CONF_SILENT_REQ = (1 << 0), CONF_SILENT_DONE = (1 << 1) @@ -380,6 +401,7 @@ typedef struct mcu_canvas_s { int layout_floor_id; switch_rgb_color_t bgcolor; switch_mutex_t *mutex; + switch_timer_t timer; switch_memory_pool_t *pool; } mcu_canvas_t; @@ -430,6 +452,7 @@ typedef struct conference_obj { char *video_layout_group; char *video_canvas_bgcolor; char *video_layout_bgcolor; + int video_timer_reset; int32_t video_write_bandwidth; switch_codec_settings_t video_codec_settings; uint32_t canvas_width; @@ -518,6 +541,7 @@ typedef struct conference_obj { mcu_canvas_t *canvas; switch_hash_t *layout_hash; switch_hash_t *layout_group_hash; + struct conf_fps video_fps; } conference_obj_t; /* Relationship with another member */ @@ -640,6 +664,22 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf SWITCH_STANDARD_API(conf_api_main); + +static int conference_set_fps(conference_obj_t *conference, float fps) +{ + int i = 0; + + for (i = 0; FPS_VALS[i].ms; i++) { + if (FPS_VALS[i].fps == fps) { + conference->video_fps = FPS_VALS[i]; + conference->video_timer_reset = 1; + return 1; + } + } + + return 0; +} + static switch_status_t conference_outcall(conference_obj_t *conference, char *conference_name, switch_core_session_t *session, @@ -1303,7 +1343,8 @@ typedef struct codec_set_s { } codec_set_t; static void write_canvas_image_to_codec_group(conference_obj_t *conference, codec_set_t *codec_set, - int codec_index, uint32_t timestamp, switch_bool_t need_refresh, switch_bool_t need_keyframe) + int codec_index, uint32_t timestamp, switch_bool_t need_refresh, + switch_bool_t need_keyframe, switch_bool_t need_reset) { conference_member_t *imember; @@ -1319,6 +1360,12 @@ static void write_canvas_image_to_codec_group(conference_obj_t *conference, code frame->m = 0; frame->timestamp = timestamp; + if (need_reset) { + int type = 1; // sum flags: 1 encoder; 2; decoder + switch_core_codec_control(&codec_set->codec, SCC_VIDEO_RESET, SCCT_INT, (void *)&type, NULL, NULL); + need_refresh = SWITCH_TRUE; + } + if (need_refresh || need_keyframe) { switch_core_codec_control(&codec_set->codec, SCC_VIDEO_REFRESH, SCCT_NONE, NULL, NULL, NULL); } @@ -1388,7 +1435,6 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread switch_codec_t *check_codec = NULL; codec_set_t *write_codecs[MAX_MUX_CODECS] = { 0 }; int buflen = SWITCH_RECOMMENDED_BUFFER_SIZE * 2; - switch_timer_t timer = { 0 }; int i = 0; int used = 0; uint32_t video_key_freq = 30000000; @@ -1419,17 +1465,23 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread init_canvas(conference, vlayout); - switch_core_timer_init(&timer, "soft", 33, 3000, conference->pool); - + conference->video_timer_reset = 1; + if (!switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) { packet = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE); } while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT) && switch_test_flag(conference, CFLAG_VIDEO_MUXING)) { - switch_bool_t need_refresh = SWITCH_FALSE, need_keyframe = SWITCH_FALSE; + switch_bool_t need_refresh = SWITCH_FALSE, need_keyframe = SWITCH_FALSE, need_reset = SWITCH_FALSE; switch_time_t now; - - switch_core_timer_next(&timer); + + if (conference->video_timer_reset) { + conference->video_timer_reset = 0; + switch_core_timer_init(&conference->canvas->timer, "soft", conference->video_fps.ms, conference->video_fps.samples, NULL); + need_reset = SWITCH_TRUE; + } + + switch_core_timer_next(&conference->canvas->timer); now = switch_micro_time_now(); @@ -1600,7 +1652,8 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread if (switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) { 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); + write_canvas_image_to_codec_group(conference, write_codecs[i], i, + conference->canvas->timer.samplecount, need_refresh, need_keyframe, need_reset); if (conference->video_write_bandwidth) { switch_core_codec_control(&write_codecs[i]->codec, SCC_VIDEO_BANDWIDTH, SCCT_INT, &conference->video_write_bandwidth, NULL, NULL); @@ -1658,7 +1711,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread } } - switch_core_timer_destroy(&timer); + switch_core_timer_destroy(&conference->canvas->timer); destroy_canvas(&conference->canvas); @@ -7761,6 +7814,32 @@ static switch_status_t conf_api_sub_vid_bandwidth(conference_obj_t *conference, return SWITCH_STATUS_SUCCESS; } +static switch_status_t conf_api_sub_vid_fps(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv) +{ + float fps = 0; + + if (!argv[2]) { + stream->write_function(stream, "Invalid input\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (!conference->canvas) { + stream->write_function(stream, "Conference is not in mixing mode\n"); + return SWITCH_STATUS_SUCCESS; + } + + fps = atof(argv[2]); + + if (conference_set_fps(conference, fps)) { + stream->write_function(stream, "FPS set to [%s]\n", argv[2]); + } else { + stream->write_function(stream, "Invalid FPS [%s]\n", argv[2]); + } + + 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; @@ -9468,6 +9547,7 @@ static api_command_t conf_api_sub_commands[] = { {"vid-banner", (void_fn_t) & conf_api_sub_vid_banner, CONF_API_SUB_MEMBER_TARGET, "vid-banner", " "}, {"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-fps", (void_fn_t) & conf_api_sub_vid_fps, CONF_API_SUB_ARGS_SPLIT, "vid-fps", ""}, {"vid-bandwidth", (void_fn_t) & conf_api_sub_vid_bandwidth, CONF_API_SUB_ARGS_SPLIT, "vid-bandwidth", ""} }; @@ -11212,6 +11292,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c char *video_canvas_bgcolor = NULL; char *video_layout_bgcolor = NULL; char *video_codec_bandwidth = NULL; + float fps = 15.0f; uint32_t max_members = 0; uint32_t announce_count = 0; char *maxmember_sound = NULL; @@ -11367,6 +11448,8 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c video_layout_bgcolor= val; } else if (!strcasecmp(var, "video-canvas-size") && !zstr(val)) { video_canvas_size = val; + } else if (!strcasecmp(var, "video-fps") && !zstr(val)) { + fps = atof(val); } else if (!strcasecmp(var, "video-codec-bandwidth") && !zstr(val)) { video_codec_bandwidth = val; } else if (!strcasecmp(var, "exit-sound") && !zstr(val)) { @@ -11580,6 +11663,14 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c conference->video_canvas_bgcolor = switch_core_strdup(conference->pool, video_canvas_bgcolor); conference->video_layout_bgcolor = switch_core_strdup(conference->pool, video_layout_bgcolor); + + if (fps) { + conference_set_fps(conference, fps); + } + + if (!conference->video_fps.ms) { + conference_set_fps(conference, 30); + } if (video_canvas_size && video_layout_name) { int w = 0, h = 0; diff --git a/src/mod/codecs/mod_vpx/mod_vpx.c b/src/mod/codecs/mod_vpx/mod_vpx.c index d1cbbe4760..67730514d0 100644 --- a/src/mod/codecs/mod_vpx/mod_vpx.c +++ b/src/mod/codecs/mod_vpx/mod_vpx.c @@ -76,6 +76,8 @@ struct vpx_context { switch_size_t last_received_timestamp; switch_bool_t last_received_complete_picture; int need_key_frame; + int need_encoder_reset; + int need_decoder_reset; int32_t change_bandwidth; uint64_t framecount; uint64_t framesum; @@ -387,6 +389,15 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t * return consume_partition(context, frame); } + if (context->need_encoder_reset != 0) { + vpx_codec_destroy(&context->encoder); + context->framesum = 0; + context->framecount = 0; + context->encoder_init = 0; + init_codec(codec); + context->need_encoder_reset = 0; + } + //d_w and d_h are messed up //printf("WTF %d %d\n", frame->img->d_w, frame->img->d_h); @@ -420,7 +431,6 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t * init_codec(codec); } - if (context->need_key_frame != 0) { // force generate a key frame switch_time_t now = switch_micro_time_now(); @@ -535,6 +545,15 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t * vpx_codec_ctx_t *decoder = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; int is_keyframe = ((*(unsigned char *)frame->data) & 0x01) ? 0 : 1; + + + + if (context->need_decoder_reset != 0) { + vpx_codec_destroy(&context->decoder); + context->decoder_init = 0; + init_codec(codec); + context->need_decoder_reset = 0; + } if (!context->decoder_init) { init_codec(codec); @@ -586,6 +605,7 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t * //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "buffered: %" SWITCH_SIZE_T_FMT ", key: %d\n", len, keyframe); + err = vpx_codec_decode(decoder, data, (unsigned int)len, NULL, 0); if (err != VPX_CODEC_OK) { @@ -643,6 +663,17 @@ static switch_status_t switch_vpx_control(switch_codec_t *codec, vpx_context_t *context = (vpx_context_t *)codec->private_info; switch(cmd) { + case SCC_VIDEO_RESET: + { + int mask = *((int *) cmd_data); + if (mask & 1) { + context->need_encoder_reset = 1; + } + if (mask & 2) { + context->need_decoder_reset = 1; + } + } + break; case SCC_VIDEO_REFRESH: context->need_key_frame = 1; break; diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 2da7671b4a..2e5661cb77 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -6747,6 +6747,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session, if (ntohl(send_msg->header.ts) != rtp_session->ts_norm.last_frame) { rtp_session->ts_norm.delta = ntohl(send_msg->header.ts) - rtp_session->ts_norm.last_frame; + //printf("WTF %d\n", rtp_session->ts_norm.delta); rtp_session->ts_norm.ts += rtp_session->ts_norm.delta; //switch_core_timer_sync(&rtp_session->timer); //printf("W00t %d\n", rtp_session->timer.samplecount);