fix: convert PTS from from frame号单位转换
This commit is contained in:
167
src/state.rs
167
src/state.rs
@@ -29,7 +29,7 @@ use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_frame_v1::{
|
|||||||
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1;
|
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_manager_v1::ZwlrScreencopyManagerV1;
|
||||||
|
|
||||||
use ffmpeg_next as ff;
|
use ffmpeg_next as ff;
|
||||||
use ffmpeg_next::ffi as ffi;
|
use ffmpeg_next::ffi;
|
||||||
|
|
||||||
use crate::args::Args;
|
use crate::args::Args;
|
||||||
use crate::avhw::{AvHwDevCtx, EncState};
|
use crate::avhw::{AvHwDevCtx, EncState};
|
||||||
@@ -153,6 +153,7 @@ pub struct State<S: CaptureSource> {
|
|||||||
pub stage: EncConstructionStage<S>,
|
pub stage: EncConstructionStage<S>,
|
||||||
pub in_flight_surface: InFlightSurface<S>,
|
pub in_flight_surface: InFlightSurface<S>,
|
||||||
pub starting_timestamp: Option<i64>,
|
pub starting_timestamp: Option<i64>,
|
||||||
|
pub first_frame: bool,
|
||||||
pub args: Args,
|
pub args: Args,
|
||||||
pub errored: bool,
|
pub errored: bool,
|
||||||
pub gm: GlobalList,
|
pub gm: GlobalList,
|
||||||
@@ -168,7 +169,8 @@ pub struct State<S: CaptureSource> {
|
|||||||
|
|
||||||
/// Scan /dev/dri for the first available DRM render node (renderD*).
|
/// Scan /dev/dri for the first available DRM render node (renderD*).
|
||||||
fn find_drm_render_node() -> Option<PathBuf> {
|
fn find_drm_render_node() -> Option<PathBuf> {
|
||||||
std::fs::read_dir("/dev/dri").ok()?
|
std::fs::read_dir("/dev/dri")
|
||||||
|
.ok()?
|
||||||
.filter_map(|e| e.ok())
|
.filter_map(|e| e.ok())
|
||||||
.filter(|e| {
|
.filter(|e| {
|
||||||
e.file_name()
|
e.file_name()
|
||||||
@@ -214,6 +216,7 @@ impl<S: CaptureSource> State<S> {
|
|||||||
},
|
},
|
||||||
in_flight_surface: InFlightSurface::None,
|
in_flight_surface: InFlightSurface::None,
|
||||||
starting_timestamp: None,
|
starting_timestamp: None,
|
||||||
|
first_frame: true,
|
||||||
fps_limit: FpsLimit::new(fps),
|
fps_limit: FpsLimit::new(fps),
|
||||||
args,
|
args,
|
||||||
errored: false,
|
errored: false,
|
||||||
@@ -268,9 +271,7 @@ impl<S: CaptureSource> State<S> {
|
|||||||
let mut surface = ff::frame::Video::empty();
|
let mut surface = ff::frame::Video::empty();
|
||||||
// SAFETY: frames_rgb_ctx is a valid AVHWFramesContext pointer; surface
|
// SAFETY: frames_rgb_ctx is a valid AVHWFramesContext pointer; surface
|
||||||
// is a freshly allocated empty Video frame.
|
// is a freshly allocated empty Video frame.
|
||||||
let ret = unsafe {
|
let ret = unsafe { ffi::av_hwframe_get_buffer(frames_rgb_ctx, surface.as_mut_ptr(), 0) };
|
||||||
ffi::av_hwframe_get_buffer(frames_rgb_ctx, surface.as_mut_ptr(), 0)
|
|
||||||
};
|
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
tracing::error!("av_hwframe_get_buffer failed: error {}", ret);
|
tracing::error!("av_hwframe_get_buffer failed: error {}", ret);
|
||||||
self.errored = true;
|
self.errored = true;
|
||||||
@@ -281,8 +282,7 @@ impl<S: CaptureSource> State<S> {
|
|||||||
// SAFETY: Setting format to DRM_PRIME and calling av_hwframe_map creates
|
// SAFETY: Setting format to DRM_PRIME and calling av_hwframe_map creates
|
||||||
// a mapped view of the GPU surface with DMA-BUF file descriptors.
|
// a mapped view of the GPU surface with DMA-BUF file descriptors.
|
||||||
unsafe {
|
unsafe {
|
||||||
(*map_frame.as_mut_ptr()).format =
|
(*map_frame.as_mut_ptr()).format = ffi::AVPixelFormat::AV_PIX_FMT_DRM_PRIME as i32;
|
||||||
ffi::AVPixelFormat::AV_PIX_FMT_DRM_PRIME as i32;
|
|
||||||
}
|
}
|
||||||
let ret = unsafe { ffi::av_hwframe_map(map_frame.as_mut_ptr(), surface.as_ptr(), 0) };
|
let ret = unsafe { ffi::av_hwframe_map(map_frame.as_mut_ptr(), surface.as_ptr(), 0) };
|
||||||
if ret < 0 {
|
if ret < 0 {
|
||||||
@@ -294,8 +294,7 @@ impl<S: CaptureSource> State<S> {
|
|||||||
// SAFETY: After av_hwframe_map with DRM_PRIME format, data[0] points to
|
// SAFETY: After av_hwframe_map with DRM_PRIME format, data[0] points to
|
||||||
// a valid AVDRMFrameDescriptor.
|
// a valid AVDRMFrameDescriptor.
|
||||||
let desc: ff::ffi::AVDRMFrameDescriptor = unsafe {
|
let desc: ff::ffi::AVDRMFrameDescriptor = unsafe {
|
||||||
let desc_ptr =
|
let desc_ptr = (*map_frame.as_ptr()).data[0] as *const ff::ffi::AVDRMFrameDescriptor;
|
||||||
(*map_frame.as_ptr()).data[0] as *const ff::ffi::AVDRMFrameDescriptor;
|
|
||||||
std::ptr::read(desc_ptr)
|
std::ptr::read(desc_ptr)
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -354,10 +353,8 @@ impl<S: CaptureSource> State<S> {
|
|||||||
where
|
where
|
||||||
S::Frame: Default,
|
S::Frame: Default,
|
||||||
{
|
{
|
||||||
let (mut surface, _drm_map, frame, buffer) = match mem::replace(
|
let (mut surface, _drm_map, frame, buffer) =
|
||||||
&mut self.in_flight_surface,
|
match mem::replace(&mut self.in_flight_surface, InFlightSurface::None) {
|
||||||
InFlightSurface::None,
|
|
||||||
) {
|
|
||||||
InFlightSurface::CopyQueued {
|
InFlightSurface::CopyQueued {
|
||||||
surface,
|
surface,
|
||||||
drm_map,
|
drm_map,
|
||||||
@@ -370,7 +367,9 @@ impl<S: CaptureSource> State<S> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let pts = (tv_sec as i64) * 1_000_000 + (tv_usec as i64);
|
let fps = self.args.fps as i64;
|
||||||
|
// PTS in frame-number units (encoder time_base = 1/fps)
|
||||||
|
let pts = (tv_sec as i64) * fps + (tv_usec as i64) * fps / 1_000_000;
|
||||||
surface.set_pts(Some(pts));
|
surface.set_pts(Some(pts));
|
||||||
drop(buffer);
|
drop(buffer);
|
||||||
let cap = match &mut self.stage {
|
let cap = match &mut self.stage {
|
||||||
@@ -385,7 +384,14 @@ impl<S: CaptureSource> State<S> {
|
|||||||
EncConstructionStage::Streaming { enc, .. } => enc,
|
EncConstructionStage::Streaming { enc, .. } => enc,
|
||||||
_ => unreachable!("already checked Streaming above"),
|
_ => unreachable!("already checked Streaming above"),
|
||||||
};
|
};
|
||||||
let should_encode = self.fps_limit.on_new_frame(S::Frame::default(), Instant::now()).is_some();
|
let should_encode = if self.first_frame {
|
||||||
|
self.first_frame = false;
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
self.fps_limit
|
||||||
|
.on_new_frame(S::Frame::default(), Instant::now())
|
||||||
|
.is_some()
|
||||||
|
};
|
||||||
if should_encode {
|
if should_encode {
|
||||||
if let Err(e) = enc.encode_frame(&surface) {
|
if let Err(e) = enc.encode_frame(&surface) {
|
||||||
tracing::error!("encode_frame failed: {}", e);
|
tracing::error!("encode_frame failed: {}", e);
|
||||||
@@ -441,7 +447,10 @@ impl<S: CaptureSource> State<S> {
|
|||||||
};
|
};
|
||||||
tracing::info!(
|
tracing::info!(
|
||||||
"Encoder initialized: {}x{} format={} bitrate={}",
|
"Encoder initialized: {}x{} format={} bitrate={}",
|
||||||
width, height, format, bitrate
|
width,
|
||||||
|
height,
|
||||||
|
format,
|
||||||
|
bitrate
|
||||||
);
|
);
|
||||||
self.stage = EncConstructionStage::Streaming {
|
self.stage = EncConstructionStage::Streaming {
|
||||||
output_info,
|
output_info,
|
||||||
@@ -458,16 +467,21 @@ impl<S: CaptureSource> State<S> {
|
|||||||
EncConstructionStage::ProbingOutputs { outputs, .. } => {
|
EncConstructionStage::ProbingOutputs { outputs, .. } => {
|
||||||
let output_count = outputs.len();
|
let output_count = outputs.len();
|
||||||
let idx = if let Some(ref name) = self.args.output_name {
|
let idx = if let Some(ref name) = self.args.output_name {
|
||||||
let pos = outputs.iter().position(|o| o.name.as_deref() == Some(name.as_str()));
|
let pos = outputs
|
||||||
|
.iter()
|
||||||
|
.position(|o| o.name.as_deref() == Some(name.as_str()));
|
||||||
match pos {
|
match pos {
|
||||||
Some(i) => Some(i),
|
Some(i) => Some(i),
|
||||||
None => {
|
None => {
|
||||||
let all_probed = outputs.iter().all(|o| o.done_count >= 2);
|
let all_probed = outputs.iter().all(|o| o.done_count >= 2);
|
||||||
if all_probed {
|
if all_probed {
|
||||||
let available: Vec<&str> = outputs.iter()
|
let available: Vec<&str> =
|
||||||
.filter_map(|o| o.name.as_deref())
|
outputs.iter().filter_map(|o| o.name.as_deref()).collect();
|
||||||
.collect();
|
tracing::error!(
|
||||||
tracing::error!("Output '{}' not found. Available outputs: {:?}", name, available);
|
"Output '{}' not found. Available outputs: {:?}",
|
||||||
|
name,
|
||||||
|
available
|
||||||
|
);
|
||||||
self.errored = true;
|
self.errored = true;
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
@@ -589,7 +603,10 @@ impl<S: CaptureSource> State<S> {
|
|||||||
|
|
||||||
tracing::info!("Selected output: {}", output_info.name);
|
tracing::info!("Selected output: {}", output_info.name);
|
||||||
if self.args.output_name.is_none() && output_count > 1 {
|
if self.args.output_name.is_none() && output_count > 1 {
|
||||||
tracing::warn!("Multiple outputs found, using '{}'. Use --output-name to select.", output_info.name);
|
tracing::warn!(
|
||||||
|
"Multiple outputs found, using '{}'. Use --output-name to select.",
|
||||||
|
output_info.name
|
||||||
|
);
|
||||||
}
|
}
|
||||||
self.stage = EncConstructionStage::EverythingButFmt {
|
self.stage = EncConstructionStage::EverythingButFmt {
|
||||||
output_info,
|
output_info,
|
||||||
@@ -620,13 +637,19 @@ impl<S: CaptureSource> Dispatch<WlRegistry, GlobalListContents> for State<S> {
|
|||||||
use wayland_client::protocol::wl_registry::Event as RegistryEvent;
|
use wayland_client::protocol::wl_registry::Event as RegistryEvent;
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
RegistryEvent::Global { name, interface, version } => {
|
RegistryEvent::Global {
|
||||||
match interface.as_str() {
|
name,
|
||||||
|
interface,
|
||||||
|
version,
|
||||||
|
} => match interface.as_str() {
|
||||||
"zwlr_screencopy_manager_v1" => {
|
"zwlr_screencopy_manager_v1" => {
|
||||||
let v = version.min(3);
|
let v = version.min(3);
|
||||||
tracing::debug!("Binding zwlr_screencopy_manager_v1 v{v} (name={name})");
|
tracing::debug!("Binding zwlr_screencopy_manager_v1 v{v} (name={name})");
|
||||||
let mgr: ZwlrScreencopyManagerV1 = registry.bind(name, v, qhandle, ());
|
let mgr: ZwlrScreencopyManagerV1 = registry.bind(name, v, qhandle, ());
|
||||||
if let EncConstructionStage::ProbingOutputs { screencopy_manager, .. } = &mut state.stage {
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
|
screencopy_manager, ..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
*screencopy_manager = Some(mgr);
|
*screencopy_manager = Some(mgr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -634,7 +657,12 @@ impl<S: CaptureSource> Dispatch<WlRegistry, GlobalListContents> for State<S> {
|
|||||||
let v = version.min(4);
|
let v = version.min(4);
|
||||||
tracing::debug!("Binding zwp_linux_dmabuf_v1 v{v} (name={name})");
|
tracing::debug!("Binding zwp_linux_dmabuf_v1 v{v} (name={name})");
|
||||||
let proxy: ZwpLinuxDmabufV1 = registry.bind(name, v, qhandle, ());
|
let proxy: ZwpLinuxDmabufV1 = registry.bind(name, v, qhandle, ());
|
||||||
if let EncConstructionStage::ProbingOutputs { dmabuf, dmabuf_feedback, .. } = &mut state.stage {
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
|
dmabuf,
|
||||||
|
dmabuf_feedback,
|
||||||
|
..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
*dmabuf = Some(proxy.clone());
|
*dmabuf = Some(proxy.clone());
|
||||||
if v >= 4 {
|
if v >= 4 {
|
||||||
let feedback = proxy.get_default_feedback(qhandle, ());
|
let feedback = proxy.get_default_feedback(qhandle, ());
|
||||||
@@ -645,10 +673,15 @@ impl<S: CaptureSource> Dispatch<WlRegistry, GlobalListContents> for State<S> {
|
|||||||
"wl_output" => {
|
"wl_output" => {
|
||||||
let v = version.min(4);
|
let v = version.min(4);
|
||||||
tracing::debug!("Binding wl_output v{v} (name={name})");
|
tracing::debug!("Binding wl_output v{v} (name={name})");
|
||||||
let output: WlOutput = registry.bind(name, v, qhandle, ());
|
let output: WlOutput = registry.bind(name, v, qhandle, OutputId(name));
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
outputs, bound_outputs, output_names, xdg_output_manager, ..
|
outputs,
|
||||||
} = &mut state.stage {
|
bound_outputs,
|
||||||
|
output_names,
|
||||||
|
xdg_output_manager,
|
||||||
|
..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
outputs.push(PartialOutputInfo::default());
|
outputs.push(PartialOutputInfo::default());
|
||||||
bound_outputs.push(output.clone());
|
bound_outputs.push(output.clone());
|
||||||
output_names.push(name);
|
output_names.push(name);
|
||||||
@@ -663,8 +696,12 @@ impl<S: CaptureSource> Dispatch<WlRegistry, GlobalListContents> for State<S> {
|
|||||||
tracing::debug!("Binding zxdg_output_manager_v1 v{v} (name={name})");
|
tracing::debug!("Binding zxdg_output_manager_v1 v{v} (name={name})");
|
||||||
let xdg_mgr: ZxdgOutputManagerV1 = registry.bind(name, v, qhandle, ());
|
let xdg_mgr: ZxdgOutputManagerV1 = registry.bind(name, v, qhandle, ());
|
||||||
if let EncConstructionStage::ProbingOutputs {
|
if let EncConstructionStage::ProbingOutputs {
|
||||||
bound_outputs, xdg_output_manager, output_names, ..
|
bound_outputs,
|
||||||
} = &mut state.stage {
|
xdg_output_manager,
|
||||||
|
output_names,
|
||||||
|
..
|
||||||
|
} = &mut state.stage
|
||||||
|
{
|
||||||
for (i, output) in bound_outputs.iter().enumerate() {
|
for (i, output) in bound_outputs.iter().enumerate() {
|
||||||
let oname = output_names.get(i).copied().unwrap_or(0);
|
let oname = output_names.get(i).copied().unwrap_or(0);
|
||||||
let output_id = OutputId(oname);
|
let output_id = OutputId(oname);
|
||||||
@@ -674,8 +711,7 @@ impl<S: CaptureSource> Dispatch<WlRegistry, GlobalListContents> for State<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
},
|
||||||
}
|
|
||||||
RegistryEvent::GlobalRemove { name } => {
|
RegistryEvent::GlobalRemove { name } => {
|
||||||
tracing::debug!("Global removed: name={name}");
|
tracing::debug!("Global removed: name={name}");
|
||||||
}
|
}
|
||||||
@@ -688,12 +724,12 @@ impl<S: CaptureSource> Dispatch<WlRegistry, GlobalListContents> for State<S> {
|
|||||||
// Dispatch<WlOutput, ()>
|
// Dispatch<WlOutput, ()>
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
impl<S: CaptureSource> Dispatch<WlOutput, ()> for State<S> {
|
impl<S: CaptureSource> Dispatch<WlOutput, OutputId> for State<S> {
|
||||||
fn event(
|
fn event(
|
||||||
state: &mut Self,
|
state: &mut Self,
|
||||||
_proxy: &WlOutput,
|
_proxy: &WlOutput,
|
||||||
event: wayland_client::protocol::wl_output::Event,
|
event: wayland_client::protocol::wl_output::Event,
|
||||||
_data: &(),
|
data: &OutputId,
|
||||||
_conn: &wayland_client::Connection,
|
_conn: &wayland_client::Connection,
|
||||||
_qhandle: &QueueHandle<State<S>>,
|
_qhandle: &QueueHandle<State<S>>,
|
||||||
) {
|
) {
|
||||||
@@ -701,15 +737,25 @@ impl<S: CaptureSource> Dispatch<WlOutput, ()> for State<S> {
|
|||||||
use wayland_client::protocol::wl_output::Mode as WlMode;
|
use wayland_client::protocol::wl_output::Mode as WlMode;
|
||||||
use wayland_client::protocol::wl_output::Transform as WlTransform;
|
use wayland_client::protocol::wl_output::Transform as WlTransform;
|
||||||
|
|
||||||
let idx = match &mut state.stage {
|
let OutputId(target_name) = data;
|
||||||
EncConstructionStage::ProbingOutputs { outputs, .. } => {
|
let idx = match &state.stage {
|
||||||
outputs.len().saturating_sub(1)
|
EncConstructionStage::ProbingOutputs { output_names, .. } => {
|
||||||
|
output_names.iter().position(|&n| n == *target_name)
|
||||||
}
|
}
|
||||||
_ => return,
|
_ => None,
|
||||||
|
};
|
||||||
|
let idx = match idx {
|
||||||
|
Some(i) => i,
|
||||||
|
None => return,
|
||||||
};
|
};
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
OutputEvent::Geometry { transform, physical_width, physical_height, .. } => {
|
OutputEvent::Geometry {
|
||||||
|
transform,
|
||||||
|
physical_width,
|
||||||
|
physical_height,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let t = match transform {
|
let t = match transform {
|
||||||
wayland_client::WEnum::Value(WlTransform::Normal) => Transform::Normal,
|
wayland_client::WEnum::Value(WlTransform::Normal) => Transform::Normal,
|
||||||
wayland_client::WEnum::Value(WlTransform::_90) => Transform::Normal90,
|
wayland_client::WEnum::Value(WlTransform::_90) => Transform::Normal90,
|
||||||
@@ -728,7 +774,12 @@ impl<S: CaptureSource> Dispatch<WlOutput, ()> for State<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OutputEvent::Mode { width, height, flags, .. } => {
|
OutputEvent::Mode {
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
flags,
|
||||||
|
..
|
||||||
|
} => {
|
||||||
let is_current = matches!(flags, wayland_client::WEnum::Value(WlMode::Current));
|
let is_current = matches!(flags, wayland_client::WEnum::Value(WlMode::Current));
|
||||||
if is_current {
|
if is_current {
|
||||||
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
if let EncConstructionStage::ProbingOutputs { outputs, .. } = &mut state.stage {
|
||||||
@@ -843,20 +894,28 @@ impl<S: CaptureSource> Dispatch<ZwpLinuxDmabufFeedbackV1, ()> for State<S> {
|
|||||||
DmabufFeedbackEvent::MainDevice { device } => {
|
DmabufFeedbackEvent::MainDevice { device } => {
|
||||||
if device.len() >= 8 {
|
if device.len() >= 8 {
|
||||||
let dev_bytes: [u8; 8] = device[..8].try_into().unwrap_or([0u8; 8]);
|
let dev_bytes: [u8; 8] = device[..8].try_into().unwrap_or([0u8; 8]);
|
||||||
let dev_t = u64::from_ne_bytes(dev_bytes);
|
let dev = u64::from_ne_bytes(dev_bytes);
|
||||||
let minor = (dev_t as u32) & 0xFFFFF;
|
let minor = ((dev & 0xFF) | ((dev >> 12) & 0xFFFFFF00)) as u32;
|
||||||
let path = PathBuf::from(format!("/dev/dri/renderD{}", minor));
|
let path = PathBuf::from(format!("/dev/dri/renderD{}", minor));
|
||||||
if path.exists() {
|
if path.exists() {
|
||||||
tracing::info!("Compositor DRM device: {} (dev_t: {})", path.display(), dev_t);
|
tracing::info!(
|
||||||
|
"Compositor DRM device: {} (dev_t: {})",
|
||||||
|
path.display(),
|
||||||
|
dev
|
||||||
|
);
|
||||||
state.drm_device_from_compositor = Some(path);
|
state.drm_device_from_compositor = Some(path);
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
"Compositor reported DRM device {} (dev_t: {}) but path does not exist",
|
"Compositor reported DRM device {} (dev_t: {}) but path does not exist",
|
||||||
path.display(), dev_t
|
path.display(),
|
||||||
|
dev
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!("main_device event with unexpected data length: {}", device.len());
|
tracing::warn!(
|
||||||
|
"main_device event with unexpected data length: {}",
|
||||||
|
device.len()
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DmabufFeedbackEvent::FormatTable { .. } => {}
|
DmabufFeedbackEvent::FormatTable { .. } => {}
|
||||||
@@ -910,12 +969,18 @@ impl Dispatch<ZwlrScreencopyFrameV1, ()> for State<CapWlrScreencopy> {
|
|||||||
) {
|
) {
|
||||||
match event {
|
match event {
|
||||||
ScreencopyFrameEvent::Buffer { .. } => {
|
ScreencopyFrameEvent::Buffer { .. } => {
|
||||||
tracing::warn!("Received SHM Buffer event — only DMA-BUF capture is supported. Ignoring.");
|
tracing::warn!(
|
||||||
|
"Received SHM Buffer event — only DMA-BUF capture is supported. Ignoring."
|
||||||
|
);
|
||||||
proxy.destroy();
|
proxy.destroy();
|
||||||
state.errored = true;
|
state.errored = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
ScreencopyFrameEvent::LinuxDmabuf { format, width, height } => {
|
ScreencopyFrameEvent::LinuxDmabuf {
|
||||||
|
format,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
} => {
|
||||||
tracing::debug!("Screencopy LinuxDmabuf: format={format}, {width}x{height}");
|
tracing::debug!("Screencopy LinuxDmabuf: format={format}, {width}x{height}");
|
||||||
if matches!(state.stage, EncConstructionStage::EverythingButFmt { .. }) {
|
if matches!(state.stage, EncConstructionStage::EverythingButFmt { .. }) {
|
||||||
state.negotiate_format(format, width, height);
|
state.negotiate_format(format, width, height);
|
||||||
@@ -928,7 +993,11 @@ impl Dispatch<ZwlrScreencopyFrameV1, ()> for State<CapWlrScreencopy> {
|
|||||||
}
|
}
|
||||||
state.on_frame_allocd((), format, width, height);
|
state.on_frame_allocd((), format, width, height);
|
||||||
}
|
}
|
||||||
ScreencopyFrameEvent::Ready { tv_sec_hi, tv_sec_lo, tv_nsec } => {
|
ScreencopyFrameEvent::Ready {
|
||||||
|
tv_sec_hi,
|
||||||
|
tv_sec_lo,
|
||||||
|
tv_nsec,
|
||||||
|
} => {
|
||||||
let tv_sec = (tv_sec_hi as u64) << 32 | tv_sec_lo as u64;
|
let tv_sec = (tv_sec_hi as u64) << 32 | tv_sec_lo as u64;
|
||||||
let tv_usec = tv_nsec / 1000;
|
let tv_usec = tv_nsec / 1000;
|
||||||
tracing::trace!("Screencopy ready: tv_sec={tv_sec}, tv_usec={tv_usec}");
|
tracing::trace!("Screencopy ready: tv_sec={tv_sec}, tv_usec={tv_usec}");
|
||||||
|
|||||||
Reference in New Issue
Block a user