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:
130
src/state.rs
130
src/state.rs
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user