fix(state,avhw): bind initial globals manually + fix filter graph crash on niri
- registry_queue_init consumes registry events during its internal roundtrip without forwarding them to Dispatch<WlRegistry>. Added bind_initial_globals() to manually iterate GlobalList and bind all initial globals (wl_output, xdg_output_manager, dmabuf, screencopy, wlr_output_manager) at State::new time. - Fix av_freep segfault in build_filter_graph: av_buffersrc_parameters_alloc returns a plain pointer, use av_free instead of av_freep (which expects pointer-to-pointer). - Fix filter graph format negotiation: remove software format filter that broke scale_vaapi hardware pipeline. Chain is now src -> scale -> sink. - Downgrade repeat_pps error to warning (not available in FFmpeg 6.x).
This commit is contained in:
+18
-14
@@ -163,8 +163,12 @@ impl EncState {
|
||||
fps: u32,
|
||||
transform: Transform,
|
||||
) -> Result<Self> {
|
||||
tracing::info!(
|
||||
"EncState::new: {width}x{height} enc={enc_width}x{enc_height} transform={transform:?}"
|
||||
);
|
||||
// 1. VAAPI device
|
||||
let hw_device_ctx = AvHwDevCtx::new_vaapi(drm_device)?;
|
||||
tracing::debug!("EncState::new: VAAPI device created");
|
||||
|
||||
// 2. Frame contexts (capture=XRGB/RGBZ, encode=NV12)
|
||||
// frames_rgb uses original capture dimensions (matches raw framebuffer)
|
||||
@@ -209,8 +213,8 @@ impl EncState {
|
||||
|
||||
// SAFETY: Set repeat_pps=1 on the encoder so PPS is inserted in every encoded frame.
|
||||
// This ensures decoders can start decoding from any frame (important for WebRTC).
|
||||
// Note: h264_metadata BSF does NOT have repeat_sps/repeat_pps options in any FFmpeg version
|
||||
// (verified on both 6.1.3 and 8.0). The encoder's own repeat_pps option is the correct approach.
|
||||
// Note: repeat_pps is only available in FFmpeg 7.0+ (not in 6.x). On older FFmpeg,
|
||||
// IDR frames carry SPS by default; PPS repetition depends on the driver.
|
||||
// For SPS repetition: IDR frames carry SPS by default, controlled by gop_size/idr_interval.
|
||||
{
|
||||
let key = CString::new("repeat_pps").unwrap();
|
||||
@@ -219,17 +223,20 @@ impl EncState {
|
||||
ffi::av_opt_set((*enc.as_mut_ptr()).priv_data, key.as_ptr(), val.as_ptr(), 0)
|
||||
};
|
||||
if ret < 0 {
|
||||
bail!("av_opt_set repeat_pps on encoder failed: error {ret}");
|
||||
tracing::warn!("av_opt_set repeat_pps failed (error {ret}), likely FFmpeg < 7.0; continuing without per-frame PPS");
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Open encoder. Video::open() returns Encoder(Video); .0 extracts the Video.
|
||||
tracing::debug!("EncState::new: opening encoder...");
|
||||
let opened = enc
|
||||
.open()
|
||||
.map_err(|e| anyhow::anyhow!("Failed to open h264_vaapi encoder: {e}"))?;
|
||||
let enc_video = opened.0;
|
||||
tracing::debug!("EncState::new: encoder opened");
|
||||
|
||||
// 5. Filter graph (inline)
|
||||
tracing::debug!("EncState::new: building filter graph...");
|
||||
let video_filter = build_filter_graph(
|
||||
&hw_device_ctx,
|
||||
&frames_rgb,
|
||||
@@ -474,11 +481,11 @@ fn build_filter_graph(
|
||||
ff::filter::find("buffer").ok_or_else(|| anyhow::anyhow!("filter 'buffer' not found"))?;
|
||||
let buffersink = ff::filter::find("buffersink")
|
||||
.ok_or_else(|| anyhow::anyhow!("filter 'buffersink' not found"))?;
|
||||
let format_filter =
|
||||
ff::filter::find("format").ok_or_else(|| anyhow::anyhow!("filter 'format' not found"))?;
|
||||
let scale_vaapi = ff::filter::find("scale_vaapi")
|
||||
.ok_or_else(|| anyhow::anyhow!("filter 'scale_vaapi' not found"))?;
|
||||
|
||||
tracing::debug!("filter_graph: filters found");
|
||||
|
||||
// buffersrc — use AVBufferSrcParameters to set hw_frames_ctx properly
|
||||
let args = format!(
|
||||
"video_size={}x{}:pix_fmt={}:time_base=1/{fps}:pixel_aspect=1/1",
|
||||
@@ -487,6 +494,7 @@ fn build_filter_graph(
|
||||
Into::<ffi::AVPixelFormat>::into(ff::format::Pixel::VAAPI) as i32,
|
||||
);
|
||||
let mut src_ctx = graph.add(&buffersrc, "in", &args)?;
|
||||
tracing::debug!("filter_graph: buffersrc added");
|
||||
|
||||
// SAFETY: av_buffersrc_parameters_alloc allocates params for the buffersrc.
|
||||
let par = unsafe { ffi::av_buffersrc_parameters_alloc() };
|
||||
@@ -504,15 +512,12 @@ fn build_filter_graph(
|
||||
};
|
||||
(*par).hw_frames_ctx = frames_rgb.ref_clone();
|
||||
let ret = ffi::av_buffersrc_parameters_set(src_ctx.as_mut_ptr(), par);
|
||||
ffi::av_freep(par as *mut _ as *mut _);
|
||||
ffi::av_free(par as *mut _);
|
||||
if ret < 0 {
|
||||
bail!("av_buffersrc_parameters_set failed: error {ret}");
|
||||
}
|
||||
}
|
||||
|
||||
// format filter: negotiate pixel format to NV12
|
||||
let mut fmt_ctx = graph.add(&format_filter, "fmt", "pix_fmts=nv12")?;
|
||||
|
||||
// scale_vaapi: hardware scaling and colourspace conversion (keeps original dimensions)
|
||||
let mut scale_ctx = graph.add(&scale_vaapi, "scale", &format!("{width}:{height}"))?;
|
||||
// SAFETY: scale_vaapi needs hw_device_ctx for VAAPI device access.
|
||||
@@ -522,9 +527,10 @@ fn build_filter_graph(
|
||||
|
||||
// buffersink
|
||||
let mut sink_ctx = graph.add(&buffersink, "out", "")?;
|
||||
tracing::debug!("filter_graph: all filters added, linking...");
|
||||
|
||||
// Build filter chain: src -> format -> scale -> [transpose] -> sink
|
||||
src_ctx.link(0, &mut fmt_ctx, 0);
|
||||
// Build filter chain: src -> scale -> [transpose] -> sink
|
||||
src_ctx.link(0, &mut scale_ctx, 0);
|
||||
|
||||
match transform {
|
||||
Transform::Normal90 | Transform::Normal270 => {
|
||||
@@ -540,7 +546,6 @@ fn build_filter_graph(
|
||||
unsafe {
|
||||
(*trans_ctx.as_mut_ptr()).hw_device_ctx = hw_dev.ref_clone();
|
||||
}
|
||||
fmt_ctx.link(0, &mut scale_ctx, 0);
|
||||
scale_ctx.link(0, &mut trans_ctx, 0);
|
||||
trans_ctx.link(0, &mut sink_ctx, 0);
|
||||
}
|
||||
@@ -548,11 +553,9 @@ fn build_filter_graph(
|
||||
tracing::warn!(
|
||||
"Normal180 transform detected; rotation correction deferred to follow-up"
|
||||
);
|
||||
fmt_ctx.link(0, &mut scale_ctx, 0);
|
||||
scale_ctx.link(0, &mut sink_ctx, 0);
|
||||
}
|
||||
_ => {
|
||||
fmt_ctx.link(0, &mut scale_ctx, 0);
|
||||
scale_ctx.link(0, &mut sink_ctx, 0);
|
||||
}
|
||||
}
|
||||
@@ -560,6 +563,7 @@ fn build_filter_graph(
|
||||
graph
|
||||
.validate()
|
||||
.map_err(|e| anyhow::anyhow!("Filter graph validation failed: {e}"))?;
|
||||
tracing::debug!("filter_graph: graph validated");
|
||||
|
||||
Ok(graph)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user