diff --git a/src/mod/applications/mod_av/avcodec.c b/src/mod/applications/mod_av/avcodec.c index 827df4df6b..573b8baaa1 100644 --- a/src/mod/applications/mod_av/avcodec.c +++ b/src/mod/applications/mod_av/avcodec.c @@ -385,6 +385,7 @@ typedef struct h264_codec_context_s { switch_image_t *img; switch_image_t *encimg; int need_key_frame; + switch_time_t last_keyframe_request; switch_bool_t nalu_28_start; int change_bandwidth; @@ -420,7 +421,7 @@ struct avcodec_globals { int debug; uint32_t max_bitrate; uint32_t rtp_slice_size; - uint32_t key_frame_min_freq; + uint32_t key_frame_min_freq; // in ms uint32_t enc_threads; uint32_t dec_threads; @@ -1567,10 +1568,14 @@ static switch_status_t switch_h264_encode(switch_codec_t *codec, switch_frame_t avframe->pts = context->pts++; - if (context->need_key_frame) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG5, "Send AV KEYFRAME\n"); + if (context->need_key_frame && (context->last_keyframe_request + avcodec_globals.key_frame_min_freq) < switch_time_now()) { + if (avcodec_globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Generate/Send AV KEYFRAME\n"); + } + avframe->pict_type = AV_PICTURE_TYPE_I; avframe->key_frame = 1; + context->last_keyframe_request = switch_time_now(); } /* encode the image */ @@ -1585,7 +1590,7 @@ GCC_DIAG_ON(deprecated-declarations) goto error; } - if (context->need_key_frame) { + if (context->need_key_frame && avframe->key_frame == 1) { avframe->pict_type = 0; avframe->key_frame = 0; context->need_key_frame = 0; @@ -1633,8 +1638,12 @@ GCC_DIAG_ON(deprecated-declarations) context->nalus[i].start = p; context->nalus[i].eat = p; - if (mod_av_globals.debug && (*p & 0x1f) == 7) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "KEY FRAME GENERATED\n"); + if ((*p & 0x1f) == 7) { // Got Keyframe + // prevent to generate key frame too frequently + context->last_keyframe_request = switch_time_now(); + if (mod_av_globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "KEY FRAME GENERATED\n"); + } } } else { context->nalus[i].len = p - context->nalus[i].start; diff --git a/src/mod/applications/mod_av/test/test_mod_av.c b/src/mod/applications/mod_av/test/test_mod_av.c index a058aa63fd..69468dbda2 100644 --- a/src/mod/applications/mod_av/test/test_mod_av.c +++ b/src/mod/applications/mod_av/test/test_mod_av.c @@ -50,7 +50,7 @@ static fctcl_init_t my_cl_options[] = { FST_CORE_BEGIN("conf") { - const char *loop_; + const char *loop_; fctcl_install(my_cl_options); loop_ = fctcl_val("--loop"); @@ -73,7 +73,11 @@ FST_CORE_BEGIN("conf") uint8_t buf[SWITCH_DEFAULT_VIDEO_SIZE + 12]; switch_frame_t frame = { 0 }; int packets = 0; + int frames = 0; + int last_key_frame = 0; + int key_frames = 0; switch_status_t encode_status; + int debug_level = 9; switch_set_string(codec_settings.video.config_profile_name, "conference"); @@ -105,6 +109,8 @@ FST_CORE_BEGIN("conf") frame.timestamp = 0; frame.img = img; + switch_core_codec_control(&codec, SCC_DEBUG, SCCT_NONE, &debug_level, SCCT_INT, NULL, NULL, NULL); + do { frame.datalen = SWITCH_DEFAULT_VIDEO_SIZE; encode_status = switch_core_codec_encode_video(&codec, &frame); @@ -120,8 +126,21 @@ FST_CORE_BEGIN("conf") if (frame.datalen == 0) break; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[%d]: %02x %02x | m=%d | %d\n", loop, buf[12], buf[13], frame.m, frame.datalen); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "[%d]: %02x %02x | m=%d | %d\n", frames, buf[12], buf[13], frame.m, frame.datalen); packets++; + + if (frame.m) frames++; + + if (frames % 20 == 2) { + switch_core_codec_control(&codec, SCC_VIDEO_GEN_KEYFRAME, SCCT_NONE, NULL, SCCT_NONE, NULL, NULL, NULL); + } + + if (buf[12] == 0x67) { + key_frames++; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Key Frame %d last=%d diff=%d\n", + key_frames, last_key_frame, frames - last_key_frame); + last_key_frame = frames; + } } } while(encode_status == SWITCH_STATUS_MORE_DATA || loop-- > 1);