diff --git a/assets/sunshine.conf b/assets/sunshine.conf index dcfb8f11..4f80cc87 100644 --- a/assets/sunshine.conf +++ b/assets/sunshine.conf @@ -46,7 +46,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 @@ -70,8 +70,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 9886547a..07793ba7 100644 --- a/sunshine/config.cpp +++ b/sunshine/config.cpp @@ -16,8 +16,6 @@ namespace config { using namespace std::literals; video_t video { - 16, // max_b_frames - 24, // gop_size 35, // crf 35, // qp @@ -160,8 +158,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);