]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-8977: Add support for NVENC H264
authorAnthony Minessale <anthm@freeswitch.org>
Wed, 23 Mar 2016 22:55:46 +0000 (17:55 -0500)
committerMichael Jerris <mike@jerris.com>
Fri, 25 Mar 2016 15:23:48 +0000 (11:23 -0400)
src/include/switch_module_interfaces.h
src/mod/applications/mod_av/avcodec.c
src/mod/applications/mod_av/avformat.c
src/switch_core_file.c
src/switch_core_media.c

index 04054f6cd4b2f89e636f8055b195f5c335cebcf2..5585e527c143dcf13d08091cfe469a34e372de14 100644 (file)
@@ -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 {
index 938612747685c6c10a70f51b82d6055236fd7eeb..d6a44351f7d1d17c89a7af155fbe2ebfcb5992fb 100644 (file)
@@ -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
 
-               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->me_range = 16;   // me_range=16
-               context->encoder_ctx->max_b_frames = 3;    // bf=3
-
-               //context->encoder_ctx->refs = 3;    // refs=3
-               
-               //context->encoder_ctx->trellis = 1; // trellis=1
+               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);
+
+                       // libx264-medium.ffpreset preset
+
+                       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->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;
index 7a9646ecc4fa167a4784f41fd06154eb5f56cc00..074fb743e863d13b1c9be06efb0f18c6696d57ce 100644 (file)
@@ -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;
index 8632e8482f5a3228482ff6a9ef42e48f1e88b120..ce75674572e21af72783190adb3da84d915270a0 100644 (file)
@@ -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) {
index 903846359548882efc5a4fc7237b8809290e518d..67e00759881fbc9faaded6b0c4e62ae577e97ef7 100644 (file)
@@ -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");
                }