somewhat stable

This commit is contained in:
2026-04-10 11:47:15 -03:00
parent e2ca18d120
commit 27c0181d77
6 changed files with 47 additions and 28 deletions

View File

@@ -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(),

View File

@@ -1,7 +1,7 @@
#!/bin/bash
# Build and run the media client (sender)
# Requires DRM master access — runs under sudo unless already root.
# Usage: ./client.sh [server_addr] e.g. ./client.sh mcrndeb:4444
# Usage: ./client.sh [server_addr] e.g. ./client.sh mcrndeb:4447
set -euo pipefail
MEDIA_DIR="$(cd "$(dirname "$0")/.." && pwd)"