From ac140fb6ddb1a755c0571381cb6b4eb3031070c4 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 29 Jan 2015 16:37:29 -0600 Subject: [PATCH] FS-7500: codec tweaks --- src/mod/codecs/mod_openh264/mod_openh264.cpp | 124 ++++++++++++------- src/mod/codecs/mod_vpx/mod_vpx.c | 34 +++-- src/switch_core_media.c | 17 ++- 3 files changed, 110 insertions(+), 65 deletions(-) diff --git a/src/mod/codecs/mod_openh264/mod_openh264.cpp b/src/mod/codecs/mod_openh264/mod_openh264.cpp index fa918565fc..0074e6146e 100644 --- a/src/mod/codecs/mod_openh264/mod_openh264.cpp +++ b/src/mod/codecs/mod_openh264/mod_openh264.cpp @@ -39,7 +39,7 @@ #include "codec_api.h" //#include "inc/logging.h" // for debug -#define FPS 30.0f // frame rate +#define FPS 15.0f // frame rate #define H264_NALU_BUFFER_SIZE 65536 #define SLICE_SIZE SWITCH_DEFAULT_VIDEO_SIZE //NALU Slice Size @@ -70,66 +70,90 @@ typedef struct h264_codec_context_s { int need_key_frame; switch_size_t last_received_timestamp; switch_bool_t last_received_complete_picture; + switch_codec_settings_t codec_settings; + unsigned int bandwidth; } h264_codec_context_t; -int FillSpecificParameters(SEncParamExt& param) { +int FillSpecificParameters(h264_codec_context_t *context) { + SEncParamExt *param; + + param = &context->encoder_params; + + if (!context->codec_settings.video.width) { + context->codec_settings.video.width = 1280; + } + + if (!context->codec_settings.video.height) { + context->codec_settings.video.height = 720; + } + + if (context->codec_settings.video.bandwidth) { + context->bandwidth = context->codec_settings.video.bandwidth; + } else { + context->bandwidth = context->codec_settings.video.width * context->codec_settings.video.height / 1024; + } + + if (context->bandwidth > 5120) { + context->bandwidth = 5120; + } + /* Test for temporal, spatial, SNR scalability */ - param.iPicWidth = 1280; // width of picture in samples - param.iPicHeight = 720; // height of picture in samples - param.iTargetBitrate = 1250000;//1280 * 720 * 8; // target bitrate desired - param.iRCMode = RC_QUALITY_MODE; // rc mode control - param.iTemporalLayerNum = 1; // layer number at temporal level - param.iSpatialLayerNum = 1; // layer number at spatial level - param.bEnableDenoise = 0; // denoise control - param.bEnableBackgroundDetection = 1; // background detection control - param.bEnableSceneChangeDetect= 1; - //param.bEnableFrameSkip = 1; - param.iMultipleThreadIdc= 1; - param.bEnableAdaptiveQuant = 1; // adaptive quantization control - param.bEnableLongTermReference = 0; // long term reference control - param.iLtrMarkPeriod = 30; - param.iLoopFilterAlphaC0Offset= 0; - param.iLoopFilterBetaOffset= 0; - param.iComplexityMode = MEDIUM_COMPLEXITY; - param.uiIntraPeriod = FPS * 3; // period of Intra frame + param->iPicWidth = 1280; // width of picture in samples + param->iPicHeight = 720; // height of picture in samples + param->iTargetBitrate = context->bandwidth; + param->iRCMode = RC_QUALITY_MODE; // rc mode control + param->iTemporalLayerNum = 1; // layer number at temporal level + param->iSpatialLayerNum = 1; // layer number at spatial level + param->bEnableDenoise = 0; // denoise control + param->bEnableBackgroundDetection = 1; // background detection control + param->bEnableSceneChangeDetect= 1; + //param->bEnableFrameSkip = 1; + param->iMultipleThreadIdc= 1; + param->bEnableAdaptiveQuant = 1; // adaptive quantization control + param->bEnableLongTermReference = 0; // long term reference control + param->iLtrMarkPeriod = 30; + param->iLoopFilterAlphaC0Offset= 0; + param->iLoopFilterBetaOffset= 0; + param->iComplexityMode = MEDIUM_COMPLEXITY; + param->uiIntraPeriod = FPS * 3; // period of Intra frame #ifdef MT_ENABLED - param.bEnableSpsPpsIdAddition = 1; + param->bEnableSpsPpsIdAddition = 1; #else - param.bEnableSpsPpsIdAddition = 0; + param->bEnableSpsPpsIdAddition = 0; #endif - param.bPrefixNalAddingCtrl = 0; + param->bPrefixNalAddingCtrl = 0; int iIndexLayer = 0; - param.sSpatialLayers[iIndexLayer].iVideoWidth = 1280; - param.sSpatialLayers[iIndexLayer].iVideoHeight = 720; - param.sSpatialLayers[iIndexLayer].fFrameRate = (double) (FPS * 1.0f); - // param.sSpatialLayers[iIndexLayer].iQualityLayerNum = 1; - param.sSpatialLayers[iIndexLayer].iSpatialBitrate = param.iTargetBitrate; - //param.sSpatialLayers[iIndexLayer].iMaxSpatialBitrate = param.iTargetBitrate; - //param.sSpatialLayers[iIndexLayer].uiLevelIdc = LEVEL_1_3; - param.sSpatialLayers[iIndexLayer].uiProfileIdc = PRO_BASELINE; + param->sSpatialLayers[iIndexLayer].iVideoWidth = 1280; + param->sSpatialLayers[iIndexLayer].iVideoHeight = 720; + param->sSpatialLayers[iIndexLayer].fFrameRate = (double) (FPS * 1.0f); + // param->sSpatialLayers[iIndexLayer].iQualityLayerNum = 1; + param->sSpatialLayers[iIndexLayer].iSpatialBitrate = param->iTargetBitrate; + //param->sSpatialLayers[iIndexLayer].iMaxSpatialBitrate = param->iTargetBitrate; + //param->sSpatialLayers[iIndexLayer].uiLevelIdc = LEVEL_1_3; + param->sSpatialLayers[iIndexLayer].uiProfileIdc = PRO_BASELINE; - param.iUsageType = CAMERA_VIDEO_REAL_TIME; - param.bEnableFrameCroppingFlag = 1; - //param.iMaxBitrate = 1250000; - //param.iTargetBitrate = 1250000; + param->iUsageType = CAMERA_VIDEO_REAL_TIME; + param->bEnableFrameCroppingFlag = 1; + //param->iMaxBitrate = 1250000; + //param->iTargetBitrate = 1250000; #ifdef MT_ENABLED - param.sSpatialLayers[iIndexLayer].sSliceCfg.uiSliceMode = SM_DYN_SLICE; - param.sSpatialLayers[iIndexLayer].sSliceCfg.sSliceArgument.uiSliceSizeConstraint = SLICE_SIZE; - param.uiMaxNalSize = SLICE_SIZE; + param->sSpatialLayers[iIndexLayer].sSliceCfg.uiSliceMode = SM_DYN_SLICE; + param->sSpatialLayers[iIndexLayer].sSliceCfg.sSliceArgument.uiSliceSizeConstraint = SLICE_SIZE; + param->uiMaxNalSize = SLICE_SIZE; #else - param.sSpatialLayers[iIndexLayer].sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; + param->sSpatialLayers[iIndexLayer].sSliceCfg.uiSliceMode = SM_SINGLE_SLICE; #endif - float fMaxFr = param.sSpatialLayers[param.iSpatialLayerNum - 1].fFrameRate; - for (int32_t i = param.iSpatialLayerNum - 2; i >= 0; --i) { - if (param.sSpatialLayers[i].fFrameRate > fMaxFr + EPSN) { - fMaxFr = param.sSpatialLayers[i].fFrameRate; + float fMaxFr = param->sSpatialLayers[param->iSpatialLayerNum - 1].fFrameRate; + for (int32_t i = param->iSpatialLayerNum - 2; i >= 0; --i) { + if (param->sSpatialLayers[i].fFrameRate > fMaxFr + EPSN) { + fMaxFr = param->sSpatialLayers[i].fFrameRate; } } - param.fMaxFrameRate = fMaxFr; + param->fMaxFrameRate = fMaxFr; return 0; } @@ -376,6 +400,10 @@ static switch_status_t switch_h264_init(switch_codec_t *codec, switch_codec_flag context = (h264_codec_context_t*)switch_core_alloc(codec->memory_pool, sizeof(h264_codec_context_t)); memset(context, 0, sizeof(*context)); + if (codec_settings) { + context->codec_settings = *codec_settings; + } + if (decoding) { WelsCreateDecoder(&context->decoder); @@ -407,7 +435,7 @@ static switch_status_t switch_h264_init(switch_codec_t *codec, switch_codec_flag goto error; } - FillSpecificParameters(context->encoder_params); + FillSpecificParameters(context); } //if (encoding | decoding) WelsStderrSetTraceLevel(10); @@ -627,9 +655,9 @@ end: switch_set_flag(frame, SFF_WAIT_KEY_FRAME); } - if (frame->img) { - switch_set_flag(frame, SFF_USE_VIDEO_TIMESTAMP); - } else { + if (!frame->img) { + //switch_set_flag(frame, SFF_USE_VIDEO_TIMESTAMP); + //} else { status = SWITCH_STATUS_MORE_DATA; } diff --git a/src/mod/codecs/mod_vpx/mod_vpx.c b/src/mod/codecs/mod_vpx/mod_vpx.c index 01fe627b4e..3bfa7ba59c 100644 --- a/src/mod/codecs/mod_vpx/mod_vpx.c +++ b/src/mod/codecs/mod_vpx/mod_vpx.c @@ -38,7 +38,6 @@ #include #include -#define FPS 15 #define SLICE_SIZE SWITCH_DEFAULT_VIDEO_SIZE #define KEY_FRAME_MIN_FREQ 1000000 @@ -64,12 +63,12 @@ struct vpx_context { int fps; int format; int intra_period; - int pts; int num; int partition_index; const vpx_codec_cx_pkt_t *pkt; int pkt_pos; vpx_codec_iter_t iter; + uint32_t last_ts; vpx_codec_ctx_t decoder; uint8_t decoder_init; switch_buffer_t *vpx_packet_buffer; @@ -99,15 +98,13 @@ static switch_status_t init_codec(switch_codec_t *codec) if (context->codec_settings.video.bandwidth) { context->bandwidth = context->codec_settings.video.bandwidth; } else { - int x = (context->codec_settings.video.width / 100) + 1; - context->bandwidth = context->codec_settings.video.width * context->codec_settings.video.height * x; + context->bandwidth = context->codec_settings.video.width * context->codec_settings.video.height / 1024; } - if (context->bandwidth > 1250000) { - context->bandwidth = 1250000; + if (context->bandwidth > 5120) { + context->bandwidth = 5120; } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_NOTICE, "VPX reset encoder picture from %dx%d to %dx%d %u BW\n", config->g_w, config->g_h, context->codec_settings.video.width, context->codec_settings.video.height, context->bandwidth); @@ -119,7 +116,7 @@ static switch_status_t init_codec(switch_codec_t *codec) config->g_h = context->codec_settings.video.height; config->rc_target_bitrate = context->bandwidth; config->g_timebase.num = 1; - config->g_timebase.den = 1000; + config->g_timebase.den = 90000; config->g_error_resilient = VPX_ERROR_RESILIENT_PARTITIONS; config->g_lag_in_frames = 0; // 0- no frame lagging @@ -374,11 +371,10 @@ static switch_status_t consume_partition(vpx_context_t *context, switch_frame_t static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t *frame) { vpx_context_t *context = (vpx_context_t *)codec->private_info; - uint32_t duration = 90000 / FPS; int width = 0; int height = 0; vpx_enc_frame_flags_t vpx_flags = 0; - + int32_t dur = 0; if (frame->flags & SFF_SAME_IMAGE) { return consume_partition(context, frame); @@ -423,7 +419,20 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t * } } - if (vpx_codec_encode(&context->encoder, (vpx_image_t *) frame->img, context->pts, duration, vpx_flags, VPX_DL_REALTIME) != VPX_CODEC_OK) { + if (context->last_ts) { + dur = frame->timestamp - context->last_ts; + if (dur < 0 || dur > 90000) { + dur = 0; + } + } + + + if (!dur) { + dur = 1; + } + + + if (vpx_codec_encode(&context->encoder, (vpx_image_t *) frame->img, frame->timestamp, dur, vpx_flags, VPX_DL_REALTIME) != VPX_CODEC_OK) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "VP8 encode error %d:%s\n", context->encoder.err, context->encoder.err_detail); @@ -431,8 +440,8 @@ static switch_status_t switch_vpx_encode(switch_codec_t *codec, switch_frame_t * return SWITCH_STATUS_FALSE; } - context->pts += duration; context->iter = NULL; + context->last_ts = frame->timestamp; return consume_partition(context, frame); } @@ -521,6 +530,7 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t * // possible packet loss switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Reset\n"); context->need_key_frame = 1; + context->last_ts = 0; switch_goto_status(SWITCH_STATUS_RESTART, end); } diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 1098c75c52..3ef020dbd2 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -1515,7 +1515,7 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t session->media_handle->mparams = params; if (!session->media_handle->mparams->video_key_freq) { - session->media_handle->mparams->video_key_freq = 5000000; + session->media_handle->mparams->video_key_freq = 30000000; } if (!session->media_handle->mparams->video_key_first) { @@ -2366,14 +2366,21 @@ static void switch_core_session_parse_codec_settings(switch_core_session_t *sess break; case SWITCH_MEDIA_TYPE_VIDEO: { - const char *bwv = switch_channel_get_variable(session->channel, "video_codec_bandwidth"); + const char *bwv = switch_channel_get_variable(session->channel, "rtp_video_max_bandwidth"); uint32_t bw = 0; + + if (!bwv) { + bwv = switch_channel_get_variable(session->channel, "rtp_video_max_bandwidth_out"); + } + if (bwv && (bw = (uint32_t) atol(bwv))) { - if (switch_stristr("kb", bwv)) { - bw *= 125; + if (switch_stristr("KB", bwv)) { + bw *= 8; } else if (switch_stristr("mb", bwv)) { - bw *= 125000; + bw *= 1024; + } else if (switch_stristr("MB", bwv)) { + bw *= 8192; } engine->codec_settings.video.bandwidth = bw; }