somewhat stable
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
//! Subprocess backend: spawn ffmpeg CLI for capture+encode.
|
||||
//!
|
||||
//! Spawns ffmpeg with the same hardware pipeline as `stream_av.sh`:
|
||||
//! kmsgrab → hwmap=derive_device=vaapi → scale_vaapi → h264_vaapi
|
||||
//! kmsgrab -vblank_source vsync → hwmap=derive_device=vaapi → scale_vaapi → h264_vaapi
|
||||
//! + PulseAudio desktop audio + mic → amix → AAC
|
||||
//!
|
||||
//! -vblank_source vsync forces a frame grab on every display vblank, regardless
|
||||
//! of page flips. Without it, kmsgrab only grabs when the compositor flips a
|
||||
//! new buffer — a static/slow screen yields 1fps.
|
||||
//!
|
||||
//! ffmpeg outputs NUT format to stdout. We demux that pipe with ffmpeg-next
|
||||
//! to get proper AVPackets (keyframe flags, timestamps) without parsing
|
||||
//! bytestreams. NUT is lighter than mpegts — no TS overhead, exact packet
|
||||
//! metadata in the container layer.
|
||||
//! bytestreams.
|
||||
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::os::unix::io::RawFd;
|
||||
@@ -76,8 +79,6 @@ pub fn run(
|
||||
while !stop_watcher.load(Ordering::Relaxed) {
|
||||
std::thread::sleep(std::time::Duration::from_millis(100));
|
||||
}
|
||||
// Send SIGINT to ffmpeg so it flushes and closes stdout,
|
||||
// which unblocks the packet iterator in demux_and_send.
|
||||
use nix::sys::signal::{kill, Signal};
|
||||
use nix::unistd::Pid;
|
||||
let _ = kill(Pid::from_raw(child_pid as i32), Signal::SIGINT);
|
||||
@@ -148,6 +149,9 @@ fn detect_default_source(pulse_server: &str) -> Option<String> {
|
||||
fn spawn_ffmpeg(cfg: &SubprocessConfig) -> Result<Child> {
|
||||
let audio = detect_audio_sources();
|
||||
|
||||
// fps filter after scale_vaapi pads/duplicates frames to fill gaps when
|
||||
// kmsgrab captures fewer frames than the target rate (e.g. compositor
|
||||
// skips flips on static content). Keeps the output stream at a stable fps.
|
||||
let filter = format!(
|
||||
"hwmap=derive_device=vaapi,scale_vaapi=w={}:h={}:format=nv12,fps={}",
|
||||
cfg.width, cfg.height, cfg.fps,
|
||||
@@ -158,6 +162,9 @@ fn spawn_ffmpeg(cfg: &SubprocessConfig) -> Result<Child> {
|
||||
"-init_hw_device".into(), format!("drm=drm:{}", cfg.device),
|
||||
"-init_hw_device".into(), "vaapi=va@drm".into(),
|
||||
// Video input (kmsgrab)
|
||||
// -vblank_source vsync: grab on every display vblank, not just page flips.
|
||||
// Without this, a static screen (e.g. talking-head meeting) gives 1fps
|
||||
// because the compositor rarely flips a new buffer.
|
||||
"-thread_queue_size".into(), "512".into(),
|
||||
"-device".into(), cfg.device.clone(),
|
||||
"-f".into(), "kmsgrab".into(),
|
||||
|
||||
Reference in New Issue
Block a user