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:
dailz
2026-04-14 20:42:05 +08:00
parent b2e5f37cf6
commit 506e5ea30e
2 changed files with 147 additions and 15 deletions

View File

@@ -225,7 +225,7 @@ impl<S: CaptureSource> State<S> {
pub fn new(gm: GlobalList, args: Args, qhandle: QueueHandle<State<S>>) -> Self {
let fps = args.fps;
let drm_device = args.drm_device.as_ref().map(PathBuf::from);
Self {
let mut state = Self {
stage: EncConstructionStage::ProbingOutputs {
outputs: Vec::new(),
bound_outputs: Vec::new(),
@@ -249,6 +249,134 @@ impl<S: CaptureSource> State<S> {
qhandle,
drm_device,
drm_device_from_compositor: None,
};
// registry_queue_init consumes registry events internally during its
// initial roundtrip and does NOT forward them to our Dispatch impl.
// We must manually bind the initial globals here.
state.bind_initial_globals();
state
}
/// Iterate over the GlobalList from registry_queue_init and bind all
/// globals we care about. This is necessary because registry_queue_init
/// consumes registry events during its internal roundtrip without forwarding
/// them to our Dispatch<WlRegistry> handler.
fn bind_initial_globals(&mut self) {
use wayland_client::globals::Global;
let globals: Vec<Global> = self.gm.contents().clone_list();
let registry = self.gm.registry();
let qhandle = &self.qhandle;
// Sort globals so that managers are bound BEFORE wl_output.
// This ensures xdg_output_manager and zwlr_output_manager are available
// when we bind wl_output, so we can immediately get xdg_output / wlr head.
let globals = {
fn priority(interface: &str) -> u8 {
match interface {
"zwlr_screencopy_manager_v1" => 0,
"zwp_linux_dmabuf_v1" => 0,
"zxdg_output_manager_v1" => 1,
"zwlr_output_manager_v1" => 1,
"wl_output" => 2,
_ => 3,
}
}
let mut g = globals;
g.sort_by_key(|g| priority(&g.interface));
g
};
for Global {
name,
interface,
version,
} in globals
{
match interface.as_str() {
"zwlr_screencopy_manager_v1" => {
let v = version.min(3);
tracing::debug!("Init: binding zwlr_screencopy_manager_v1 v{v} (name={name})");
let mgr: ZwlrScreencopyManagerV1 = registry.bind(name, v, qhandle, ());
if let EncConstructionStage::ProbingOutputs {
screencopy_manager, ..
} = &mut self.stage
{
*screencopy_manager = Some(mgr);
}
}
"zwp_linux_dmabuf_v1" => {
let v = version.min(4);
tracing::debug!("Init: binding zwp_linux_dmabuf_v1 v{v} (name={name})");
let proxy: ZwpLinuxDmabufV1 = registry.bind(name, v, qhandle, ());
if let EncConstructionStage::ProbingOutputs {
dmabuf,
dmabuf_feedback,
..
} = &mut self.stage
{
*dmabuf = Some(proxy.clone());
if v >= 4 {
let feedback = proxy.get_default_feedback(qhandle, ());
*dmabuf_feedback = Some(feedback);
}
}
}
"zxdg_output_manager_v1" => {
let v = version.min(3);
tracing::debug!("Init: binding zxdg_output_manager_v1 v{v} (name={name})");
let xdg_mgr: ZxdgOutputManagerV1 = registry.bind(name, v, qhandle, ());
if let EncConstructionStage::ProbingOutputs {
bound_outputs,
xdg_output_manager,
output_names,
..
} = &mut self.stage
{
for (i, output) in bound_outputs.iter().enumerate() {
let oname = output_names.get(i).copied().unwrap_or(0);
let output_id = OutputId(oname);
xdg_mgr.get_xdg_output(output, qhandle, output_id);
}
*xdg_output_manager = Some(xdg_mgr);
}
}
"zwlr_output_manager_v1" => {
let v = version.min(4);
tracing::debug!("Init: binding zwlr_output_manager_v1 v{v} (name={name})");
let mgr: ZwlrOutputManagerV1 = registry.bind(name, v, qhandle, ());
if let EncConstructionStage::ProbingOutputs {
wlr_output_manager, ..
} = &mut self.stage
{
*wlr_output_manager = Some(mgr);
}
}
"wl_output" => {
let v = version.min(4);
tracing::debug!("Init: binding wl_output v{v} (name={name})");
let output: WlOutput = registry.bind(name, v, qhandle, OutputId(name));
if let EncConstructionStage::ProbingOutputs {
outputs,
bound_outputs,
output_names,
xdg_output_manager,
..
} = &mut self.stage
{
outputs.push(PartialOutputInfo::default());
bound_outputs.push(output.clone());
output_names.push(name);
if let Some(xdg_mgr) = xdg_output_manager {
let output_id = OutputId(name);
xdg_mgr.get_xdg_output(&output, qhandle, output_id);
}
}
}
_ => {}
}
}
}