Raise Cast Streaming mirroring to 1080p, retune bitrate range to match
User is moving to a faster (150 Mbps) network and wants 1080p. Raised build_video_pipeline_for_streaming and VideoParams::default() together (they must agree -- see caststream.rs's doc comment on why a resolution mismatch there is a protocol violation, not just soft video). Left build_video_pipeline (the HLS/DLNA path) at 720p -- that one's 1280x720 choice is about an older Default Media Receiver's decoder profile/level, unrelated to what's changing here. Bitrate ceiling raised from 4-8x scaling but deliberately not straight back up to the old 8 Mbps: real testing tonight showed the AIMD probe pins to whatever MAX_BITRATE_KBPS is for the entire session once estimated_bandwidth_bps() reports (unreliably -- flat ~20 Mbps most of a session that was visibly stuttering) that there's headroom, and 8 Mbps sustained was more than the previous network+receiver could hold. 6 Mbps is a solid target for 1080p30 on its own merits. MIN_BITRATE_KBPS bumped 1000->1500 to match (1080p needs more of a floor than 720p did before it's a wall of blocking artifacts).
This commit is contained in:
parent
1ee607b5e9
commit
a058482b39
3 changed files with 38 additions and 12 deletions
|
|
@ -52,12 +52,22 @@ impl Default for VideoParams {
|
||||||
// encodes (`breadcast-core/src/pipeline/mod.rs`), not just what
|
// encodes (`breadcast-core/src/pipeline/mod.rs`), not just what
|
||||||
// we'd like to send -- this OFFER's resolution is what the
|
// we'd like to send -- this OFFER's resolution is what the
|
||||||
// receiver allocates its decoder/output surface for. Advertising
|
// receiver allocates its decoder/output surface for. Advertising
|
||||||
// 1920x1080 while actually sending 1280x720 frames is a real
|
// a resolution other than what's actually sent is a real
|
||||||
// protocol mismatch that plausibly explains a receiver decoder
|
// protocol mismatch that plausibly explains a receiver decoder
|
||||||
// corrupting/freezing rather than just looking soft.
|
// corrupting/freezing rather than just looking soft.
|
||||||
width: 1280,
|
width: 1920,
|
||||||
height: 720,
|
height: 1080,
|
||||||
max_bitrate_bps: 8_000_000,
|
// Kept equal to `breadcastd::cast_mirror::MAX_BITRATE_KBPS *
|
||||||
|
// 1000` -- see that constant's doc comment for why 8 Mbps
|
||||||
|
// (this struct's previous value) isn't used here even though
|
||||||
|
// 1080p can look better with more headroom: real hardware
|
||||||
|
// testing showed the AIMD probe pinning to whatever this
|
||||||
|
// ceiling is for the entire session once the estimator reports
|
||||||
|
// (unreliably) that there's room, and 8 Mbps sustained was more
|
||||||
|
// than the previous network+receiver could actually hold,
|
||||||
|
// producing repeated multi-second freezes rather than just
|
||||||
|
// softer video.
|
||||||
|
max_bitrate_bps: 6_000_000,
|
||||||
max_frame_rate_numerator: 30,
|
max_frame_rate_numerator: 30,
|
||||||
max_frame_rate_denominator: 1,
|
max_frame_rate_denominator: 1,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -150,12 +150,19 @@ pub fn build_video_pipeline_for_streaming(
|
||||||
) -> Result<(gst::Pipeline, gst_app::AppSink, gst::Element)> {
|
) -> Result<(gst::Pipeline, gst_app::AppSink, gst::Element)> {
|
||||||
gst::init().context("failed to initialize GStreamer")?;
|
gst::init().context("failed to initialize GStreamer")?;
|
||||||
|
|
||||||
// Same 1280x720@30 Main-profile baseline as build_video_pipeline, for
|
// 1920x1080@30 Main profile -- raised from the earlier 1280x720
|
||||||
// the same reason (see its doc comment) -- broad decoder compatibility
|
// baseline (kept in `build_video_pipeline`'s HLS path, which targets a
|
||||||
// first, revisit upward once a specific device's real ceiling is known.
|
// different, less capable receiver -- see its doc comment) once real
|
||||||
|
// hardware testing showed the actual bottleneck on the *previous*
|
||||||
|
// network wasn't resolution but the encoder being driven well past
|
||||||
|
// what that link/receiver could sustain (see `MAX_BITRATE_KBPS` in
|
||||||
|
// `breadcastd::cast_mirror`). Must stay equal to `VideoParams::default`
|
||||||
|
// in `caststream.rs` -- the OFFER's advertised resolution and what's
|
||||||
|
// actually encoded disagreeing is a protocol-level mismatch, not just
|
||||||
|
// soft video (see that struct's doc comment for what that caused).
|
||||||
let pipeline_str = "pipewiresrc path=%VIDEO_NODE_ID% do-timestamp=true ! \
|
let pipeline_str = "pipewiresrc path=%VIDEO_NODE_ID% do-timestamp=true ! \
|
||||||
videoconvert ! videoscale ! videorate ! \
|
videoconvert ! videoscale ! videorate ! \
|
||||||
video/x-raw,format=NV12,width=1280,height=720,framerate=30/1 ! \
|
video/x-raw,format=NV12,width=1920,height=1080,framerate=30/1 ! \
|
||||||
vah264enc name=venc bitrate=4000 key-int-max=60 rate-control=cbr ! \
|
vah264enc name=venc bitrate=4000 key-int-max=60 rate-control=cbr ! \
|
||||||
video/x-h264,profile=main ! \
|
video/x-h264,profile=main ! \
|
||||||
h264parse name=h264parse config-interval=-1 ! \
|
h264parse name=h264parse config-interval=-1 ! \
|
||||||
|
|
|
||||||
|
|
@ -29,14 +29,23 @@ use crate::daemon::DaemonCommand;
|
||||||
/// `vah264enc` with, since [`bitrate_control_step`] treats it as the value
|
/// `vah264enc` with, since [`bitrate_control_step`] treats it as the value
|
||||||
/// already in effect at t=0.
|
/// already in effect at t=0.
|
||||||
const INITIAL_BITRATE_KBPS: u32 = 4000;
|
const INITIAL_BITRATE_KBPS: u32 = 4000;
|
||||||
/// Never encode below this. 720p30 below roughly 1 Mbps is a wall of
|
/// Never encode below this. 1080p30 below roughly 1.5 Mbps is a wall of
|
||||||
/// blocking artifacts -- if the link genuinely can't carry that, dropping
|
/// blocking artifacts -- if the link genuinely can't carry that, dropping
|
||||||
/// frames is a better failure mode than shipping unwatchable video.
|
/// frames is a better failure mode than shipping unwatchable video.
|
||||||
const MIN_BITRATE_KBPS: u32 = 1000;
|
const MIN_BITRATE_KBPS: u32 = 1500;
|
||||||
/// Never encode above this, regardless of how much headroom the estimator
|
/// Never encode above this, regardless of how much headroom the estimator
|
||||||
/// reports. Matches `VideoParams::default().max_bitrate_bps`, i.e. what the
|
/// reports. Matches `VideoParams::default().max_bitrate_bps`, i.e. what the
|
||||||
/// OFFER told the receiver to expect.
|
/// OFFER told the receiver to expect -- see that constant's doc comment for
|
||||||
const MAX_BITRATE_KBPS: u32 = 8000;
|
/// why this is 6 Mbps and not higher: real hardware testing showed the AIMD
|
||||||
|
/// probe below pinning to whatever this ceiling is for the *entire* session
|
||||||
|
/// (the estimator it trusts read a suspiciously flat ~20 Mbps almost the
|
||||||
|
/// whole time), and 8 Mbps sustained was more than the previous
|
||||||
|
/// network+receiver could actually hold without repeated multi-second
|
||||||
|
/// freezes. 6 Mbps is a solid target for 1080p30 on its own merits, not
|
||||||
|
/// just a defensive number -- revisit upward only with real evidence this
|
||||||
|
/// specific link+receiver can sustain more, not just because the estimator
|
||||||
|
/// claims there's headroom.
|
||||||
|
const MAX_BITRATE_KBPS: u32 = 6000;
|
||||||
|
|
||||||
pub struct CastMirrorSession {
|
pub struct CastMirrorSession {
|
||||||
pipeline: gst::Pipeline,
|
pipeline: gst::Pipeline,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue