diff --git a/libs/hwcodec/cpp/common/util.cpp b/libs/hwcodec/cpp/common/util.cpp index 0894f4eb..a2762aab 100644 --- a/libs/hwcodec/cpp/common/util.cpp +++ b/libs/hwcodec/cpp/common/util.cpp @@ -397,6 +397,14 @@ struct CodecOptions { bool set_rate_control(AVCodecContext *c, const std::string &name, int rc, int q) { + // Remote-desktop content is usually sparse. VBR avoids padding static + // frames up to the target bitrate while allowing short bursts for screen + // changes. Keep those bursts bounded at twice the target bitrate. + if (rc == RC_VBR && c->bit_rate > 0) { + c->rc_max_rate = c->bit_rate * 2; + c->rc_buffer_size = c->rc_max_rate; + } + if (name.find("vaapi") != std::string::npos && rc == RC_CQ) { // Used only after the normal bitrate-based VAAPI initialization fails. // Some drivers, including Intel iHD on Jasper Lake, expose CQP as their @@ -495,6 +503,10 @@ bool set_others(void *priv_data, const std::string &name) { bool change_bit_rate(AVCodecContext *c, const std::string &name, int kbs) { if (kbs > 0) { c->bit_rate = kbs * 1000; + if (c->rc_max_rate > 0 && name.find("qsv") == std::string::npos) { + c->rc_max_rate = c->bit_rate * 2; + c->rc_buffer_size = c->rc_max_rate; + } if (name.find("qsv") != std::string::npos) { c->rc_max_rate = c->bit_rate; } diff --git a/src/video/codec/h264.rs b/src/video/codec/h264.rs index 13d7a3a8..8b0ac59a 100644 --- a/src/video/codec/h264.rs +++ b/src/video/codec/h264.rs @@ -198,7 +198,7 @@ pub fn get_available_encoders(width: u32, height: u32) -> Vec { align: 1, fps: 30, gop: 30, - rc: RateControl::RC_CBR, + rc: RateControl::RC_VBR, quality: Quality::Quality_Low, // Use low quality preset for fastest encoding (ultrafast) kbs: 2000, q: 23, @@ -297,7 +297,7 @@ impl H264Encoder { align: 1, fps: config.fps as i32, gop: config.gop_size as i32, - rc: RateControl::RC_CBR, + rc: RateControl::RC_VBR, quality: Quality::Quality_Low, // Use low quality preset for fastest encoding (lowest latency) kbs: config.bitrate_kbps as i32, q: 23,