diff --git a/src/include/switch_module_interfaces.h b/src/include/switch_module_interfaces.h index 04054f6cd4..5585e527c1 100644 --- a/src/include/switch_module_interfaces.h +++ b/src/include/switch_module_interfaces.h @@ -326,6 +326,7 @@ typedef struct switch_mm_s { int vbuf; switch_video_profile_t vprofile; switch_video_encode_speed_t vencspd; + uint8_t try_hardware_encoder; } switch_mm_t; /*! an abstract representation of a file handle (some parameters based on compat with libsndfile) */ @@ -633,6 +634,7 @@ struct switch_video_codec_settings { uint32_t bandwidth; int32_t width; int32_t height; + uint8_t try_hardware_encoder; }; union switch_codec_settings { diff --git a/src/mod/applications/mod_av/avcodec.c b/src/mod/applications/mod_av/avcodec.c index 9386127476..d6a44351f7 100644 --- a/src/mod/applications/mod_av/avcodec.c +++ b/src/mod/applications/mod_av/avcodec.c @@ -188,6 +188,7 @@ typedef struct h264_codec_context_s { our_h264_nalu_t nalus[MAX_NALUS]; enum AVCodecID av_codec_id; uint16_t last_seq; // last received frame->seq + int hw_encoder; } h264_codec_context_t; static uint8_t ff_input_buffer_padding[FF_INPUT_BUFFER_PADDING_SIZE] = { 0 }; @@ -815,7 +816,20 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt { int sane = 0; - if (!context->encoder) context->encoder = avcodec_find_encoder(context->av_codec_id); + if (!context->encoder) { + if (context->av_codec_id == AV_CODEC_ID_H264) { + if (context->codec_settings.video.try_hardware_encoder && (context->encoder = avcodec_find_encoder_by_name("nvenc_h264"))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "NVENC HW CODEC ENABLED\n"); + context->hw_encoder = 1; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "NVENC HW CODEC NOT PRESENT\n"); + } + } + + if (!context->encoder) { + context->encoder = avcodec_find_encoder(context->av_codec_id); + } + } if (!context->encoder) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Cannot find encoder id: %d\n", context->av_codec_id); @@ -891,39 +905,42 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt } else if (context->av_codec_id == AV_CODEC_ID_H264) { context->encoder_ctx->profile = FF_PROFILE_H264_BASELINE; context->encoder_ctx->level = 41; - av_opt_set(context->encoder_ctx->priv_data, "preset", "veryfast", 0); - av_opt_set(context->encoder_ctx->priv_data, "tune", "zerolatency", 0); - av_opt_set(context->encoder_ctx->priv_data, "profile", "baseline", 0); - //av_opt_set_int(context->encoder_ctx->priv_data, "slice-max-size", SLICE_SIZE, 0); - // libx264-medium.ffpreset preset + if (context->hw_encoder) { + av_opt_set(context->encoder_ctx->priv_data, "preset", "llhq", 0); + + } else { + av_opt_set(context->encoder_ctx->priv_data, "preset", "veryfast", 0); + av_opt_set(context->encoder_ctx->priv_data, "tune", "zerolatency", 0); + av_opt_set(context->encoder_ctx->priv_data, "profile", "baseline", 0); + //av_opt_set_int(context->encoder_ctx->priv_data, "slice-max-size", SLICE_SIZE, 0); - context->encoder_ctx->coder_type = 1; // coder = 1 - context->encoder_ctx->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop - context->encoder_ctx->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1 - context->encoder_ctx->me_method=ME_HEX; // me_method=hex - //context->encoder_ctx->me_subpel_quality = 7; // subq=7 + // libx264-medium.ffpreset preset - context->encoder_ctx->me_range = 16; // me_range=16 - context->encoder_ctx->max_b_frames = 3; // bf=3 + context->encoder_ctx->coder_type = 1; // coder = 1 + context->encoder_ctx->flags|=CODEC_FLAG_LOOP_FILTER; // flags=+loop + context->encoder_ctx->me_cmp|= 1; // cmp=+chroma, where CHROMA = 1 + context->encoder_ctx->me_method=ME_HEX; // me_method=hex + //context->encoder_ctx->me_subpel_quality = 7; // subq=7 - //context->encoder_ctx->refs = 3; // refs=3 - - //context->encoder_ctx->trellis = 1; // trellis=1 + context->encoder_ctx->me_range = 16; // me_range=16 + context->encoder_ctx->max_b_frames = 3; // bf=3 + + //context->encoder_ctx->refs = 3; // refs=3 + + // libx264-medium.ffpreset preset + context->encoder_ctx->gop_size = 250; // g=250 + context->encoder_ctx->keyint_min = 25; // keyint_min=25 + context->encoder_ctx->scenechange_threshold = 40; // sc_threshold=40 + context->encoder_ctx->i_quant_factor = 0.71; // i_qfactor=0.71 + context->encoder_ctx->b_frame_strategy = 1; // b_strategy=1 + context->encoder_ctx->qcompress = 0.6; // qcomp=0.6 + context->encoder_ctx->qmin = 10; // qmin=10 + context->encoder_ctx->qmax = 51; // qmax=51 + context->encoder_ctx->max_qdiff = 4; // qdiff=4 + } } - - // libx264-medium.ffpreset preset - context->encoder_ctx->gop_size = 250; // g=250 - context->encoder_ctx->keyint_min = 25; // keyint_min=25 - context->encoder_ctx->scenechange_threshold = 40; // sc_threshold=40 - context->encoder_ctx->i_quant_factor = 0.71; // i_qfactor=0.71 - context->encoder_ctx->b_frame_strategy = 1; // b_strategy=1 - context->encoder_ctx->qcompress = 0.6; // qcomp=0.6 - context->encoder_ctx->qmin = 10; // qmin=10 - context->encoder_ctx->qmax = 51; // qmax=51 - context->encoder_ctx->max_qdiff = 4; // qdiff=4 - - + if (avcodec_open2(context->encoder_ctx, context->encoder, NULL) < 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not open codec\n"); return SWITCH_STATUS_FALSE; diff --git a/src/mod/applications/mod_av/avformat.c b/src/mod/applications/mod_av/avformat.c index 7a9646ecc4..074fb743e8 100644 --- a/src/mod/applications/mod_av/avformat.c +++ b/src/mod/applications/mod_av/avformat.c @@ -282,8 +282,15 @@ static switch_status_t add_stream(MediaStream *mst, AVFormatContext *fc, AVCodec int buffer_bytes = 2097152; /* 2 mb */ int fps = 15; - /* find the encoder */ - *codec = avcodec_find_encoder(codec_id); + if (mm->try_hardware_encoder && codec_id == AV_CODEC_ID_H264) { + *codec = avcodec_find_encoder_by_name("nvenc_h264"); + } + + if (!*codec) { + /* find the encoder */ + *codec = avcodec_find_encoder(codec_id); + } + if (!(*codec)) { // switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not find encoder for '%s'\n", avcodec_get_name(codec_id)); return status; diff --git a/src/switch_core_file.c b/src/switch_core_file.c index 8632e8482f..ce75674572 100644 --- a/src/switch_core_file.c +++ b/src/switch_core_file.c @@ -88,6 +88,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, fh->mm.ab = 128; fh->mm.vencspd = SWITCH_VIDEO_ENCODE_SPEED_DEFAULT; fh->mm.vprofile = SWITCH_VIDEO_PROFILE_BASELINE; + fh->mm.try_hardware_encoder = 1; if (*file_path == '{') { char *timeout; @@ -168,6 +169,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, } } + if ((val = switch_event_get_header(fh->params, "try_hardware_encoder"))) { + fh->mm.try_hardware_encoder = switch_true(val); + } + if ((val = switch_event_get_header(fh->params, "fps"))) { float ftmp = atof(val); if (ftmp > 0.0f) { diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 9038463595..67e0075988 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -1665,6 +1665,7 @@ SWITCH_DECLARE(switch_status_t) switch_media_handle_create(switch_media_handle_t session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].payload_map = switch_core_alloc(session->pool, sizeof(payload_map_t)); session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].cur_payload_map = session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].payload_map; session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].cur_payload_map->current = 1; + session->media_handle->engines[SWITCH_MEDIA_TYPE_VIDEO].codec_settings.video.try_hardware_encoder = 1; switch_channel_set_flag(session->channel, CF_DTLS_OK); @@ -2657,10 +2658,13 @@ static void switch_core_session_parse_codec_settings(switch_core_session_t *sess break; case SWITCH_MEDIA_TYPE_VIDEO: { uint32_t system_bw = 0; + const char *var = NULL, *bwv; - const char *bwv = switch_channel_get_variable(session->channel, "rtp_video_max_bandwidth"); - - if (!bwv) { + if ((var = switch_channel_get_variable(session->channel, "video_try_hardare_encoder"))) { + engine->codec_settings.video.try_hardware_encoder = switch_true(var); + } + + if (!(bwv = switch_channel_get_variable(session->channel, "rtp_video_max_bandwidth"))) { bwv = switch_channel_get_variable(session->channel, "rtp_video_max_bandwidth_out"); }