From 32b6f8a3951b39c531b17d846bd1baba018c786a Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Fri, 17 Jan 2020 18:45:14 -0800 Subject: [PATCH] Optimize encoding parameters for low-latency --- assets/sunshine.conf | 4 +--- sunshine/config.cpp | 4 ---- sunshine/config.h | 2 -- sunshine/stream.cpp | 1 + sunshine/video.cpp | 16 +++++++++++----- sunshine/video.h | 1 + 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/assets/sunshine.conf b/assets/sunshine.conf index 15237110..d59a01d6 100644 --- a/assets/sunshine.conf +++ b/assets/sunshine.conf @@ -45,7 +45,7 @@ ping_timeout = 2000 # The file where configuration for the different applications that Sunshine can run during a stream # file_apps = apps.json -# How much error correcting packets must be send for every video max_b_frames +# How much error correcting packets must be send for every video # This is just some random number, don't know the optimal value # The higher fec_percentage, the lower space for the actual data to send per frame there is fec_percentage = 10 @@ -69,8 +69,6 @@ fec_percentage = 10 # FFmpeg software encoding parameters # Honestly, I have no idea what the optimal values would be. # Play around with this :) -max_b_frames = 4 -gop_size = 24 # Constant Rate Factor. Between 1 and 52. It allows QP to go up during motion and down with still image, resulting in constant perceived quality # Higher value means more compression, but less quality diff --git a/sunshine/config.cpp b/sunshine/config.cpp index 6d2c315e..5d2ac09c 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -14,8 +14,6 @@ namespace config { using namespace std::literals; video_t video { - 16, // max_b_frames - 24, // gop_size 35, // crf 35, // qp @@ -158,8 +156,6 @@ void parse_file(const char *file) { std::cout << "["sv << name << "] -- ["sv << val << ']' << std::endl; } - int_f(vars, "max_b_frames", video.max_b_frames); - int_f(vars, "gop_size", video.gop_size); int_f(vars, "crf", video.crf); int_f(vars, "qp", video.qp); int_f(vars, "threads", video.threads); diff --git a/sunshine/config.h b/sunshine/config.h index 4b24655d..f8540ed8 100644 --- a/sunshine/config.h +++ b/sunshine/config.h @@ -7,8 +7,6 @@ namespace config { struct video_t { // ffmpeg params - int max_b_frames; - int gop_size; int crf; // higher == more compression and less quality int qp; // higher == more compression and less quality, ignored if crf != 0 diff --git a/sunshine/stream.cpp b/sunshine/stream.cpp index 3fcf7f4e..d67cefd8 100644 --- a/sunshine/stream.cpp +++ b/sunshine/stream.cpp @@ -970,6 +970,7 @@ void cmd_announce(host_t &host, peer_t peer, msg_t &&req) { config.monitor.framerate = util::from_view(args.at("x-nv-video[0].maxFPS"sv)); config.monitor.bitrate = util::from_view(args.at("x-nv-vqos[0].bw.maximumBitrateKbps"sv)); config.monitor.slicesPerFrame = util::from_view(args.at("x-nv-video[0].videoEncoderSlicesPerFrame"sv)); + config.monitor.numRefFrames = util::from_view(args.at("x-nv-video[0].maxNumReferenceFrames"sv)); } catch(std::out_of_range &) { diff --git a/sunshine/video.cpp b/sunshine/video.cpp index 7a10b04d..11eb886f 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -98,12 +98,20 @@ void encodeThread( ctx->time_base = AVRational{1, framerate}; ctx->framerate = AVRational{framerate, 1}; ctx->pix_fmt = AV_PIX_FMT_YUV420P; - ctx->max_b_frames = config::video.max_b_frames; - ctx->has_b_frames = 1; + + // B-frames delay decoder output, so never use them + ctx->max_b_frames = 0; + + // Use an infinite GOP length since I-frames are generated on demand + ctx->gop_size = std::numeric_limits::max(); + ctx->keyint_min = ctx->gop_size; + + // Some client decoders have limits on the number of reference frames + ctx->refs = config.numRefFrames; ctx->slices = config.slicesPerFrame; ctx->thread_type = FF_THREAD_SLICE; - ctx->thread_count = config::video.threads; + ctx->thread_count = std::min(ctx->slices, config::video.threads); AVDictionary *options {nullptr}; @@ -119,11 +127,9 @@ void encodeThread( ctx->rc_min_rate = config.bitrate; } else if(config::video.crf != 0) { - ctx->gop_size = config::video.gop_size; av_dict_set_int(&options, "crf", config::video.crf, 0); } else { - ctx->gop_size = config::video.gop_size; av_dict_set_int(&options, "qp", config::video.qp, 0); } diff --git a/sunshine/video.h b/sunshine/video.h index f2f793d5..3d0a25b0 100644 --- a/sunshine/video.h +++ b/sunshine/video.h @@ -21,6 +21,7 @@ struct config_t { int framerate; int bitrate; int slicesPerFrame; + int numRefFrames; }; void capture_display(packet_queue_t packets, idr_event_t idr_events, config_t config);