- commit
- 5a9a500dd488b6e956270c345ba8d159e31de8fa
- parent
- 2296fc01edf217ad56591554b838d8aa20f2e83e
- author
- Dami <dami.etoile@gmail.com>
| M | src-tauri/ | 85 | ++++++++++++++++++++---------- |
@@ -116,15 +116,17 @@ async fn stream_frames(conn: Connection, app: &AppHandle) -> anyhow::Result<()>
116116 return Ok(());117117 }118118 119- let (w, h) = {119+ // xcap is !Send; run the one-time dimension probe on a blocking thread120+ let (w, h) = tokio::task::spawn_blocking(|| -> anyhow::Result<(usize, usize)> {120121 let monitors = xcap::Monitor::all().context("failed to enumerate monitors")?;121122 let mon = monitors122123 .into_iter()123124 .next()124125 .ok_or_else(|| anyhow::anyhow!("no monitors found"))?;125126 let img = mon.capture_image()?;126- (img.width() as usize, img.height() as usize)127- };127+ Ok((img.width() as usize, img.height() as usize))128+ })129+ .await??;128130 eprintln!("[host] screen resolution: {}x{}", w, h);129131 130132 if ffmpeg_available() {@@ -589,36 +591,63 @@ async fn stream_frames_xcap(
589591 recv: &mut iroh::endpoint::RecvStream,590592 app: &AppHandle,591593 ) -> anyhow::Result<()> {592- let monitors = xcap::Monitor::all().context("failed to enumerate monitors")?;593- let monitor = monitors594- .into_iter()595- .next()596- .ok_or_else(|| anyhow::anyhow!("no monitors found"))?;594+ use std::sync::mpsc;595+596+ // xcap::Monitor and openh264::Encoder are !Send; run them on a dedicated thread597+ // and communicate frames back via a channel.598+ let (tx, rx) = mpsc::channel::<anyhow::Result<(usize, usize, Vec<u8>, bool, f64, f64)>>();599+600+ let capture_thread = std::thread::spawn(move || -> anyhow::Result<()> {601+ let monitors = xcap::Monitor::all().context("failed to enumerate monitors")?;602+ let monitor = monitors603+ .into_iter()604+ .next()605+ .ok_or_else(|| anyhow::anyhow!("no monitors found"))?;606+ let mut encoder = Encoder::new().context("failed to create H.264 encoder")?;607+608+ loop {609+ let result = (|| -> anyhow::Result<_> {610+ let capture_start = Instant::now();611+ let image = monitor.capture_image()?;612+ let capture_ms = capture_start.elapsed().as_secs_f64() * 1000.0;613+614+ let rgb_image = image::DynamicImage::ImageRgba8(image).to_rgb8();615+ let (w, h) = (rgb_image.width() as usize, rgb_image.height() as usize);616+617+ let encode_start = Instant::now();618+ let rgb_source = RgbSliceU8::new(rgb_image.as_raw(), (w, h));619+ let yuv = YUVBuffer::from_rgb8_source(rgb_source);620+ let (h264_data, is_keyframe) = {621+ let bitstream = encoder.encode(&yuv).context("H.264 encode failed")?;622+ let kf = matches!(623+ bitstream.frame_type(),624+ openh264::encoder::FrameType::I | openh264::encoder::FrameType::IDR625+ );626+ (bitstream.to_vec(), kf)627+ };628+ let encode_ms = encode_start.elapsed().as_secs_f64() * 1000.0;629+ Ok((w, h, h264_data, is_keyframe, capture_ms, encode_ms))630+ })();631+632+ if tx.send(result).is_err() {633+ break; // receiver dropped — stop634+ }635+ }636+ Ok(())637+ });597638 598- let mut encoder = Encoder::new().context("failed to create H.264 encoder")?;599639 let mut frame_count = 0u32;600640 let start = Instant::now();601641 602642 loop {603- let capture_start = Instant::now();604- let image = monitor.capture_image()?;605- let capture_ms = capture_start.elapsed().as_secs_f64() * 1000.0;606-607- let rgb_image = image::DynamicImage::ImageRgba8(image).to_rgb8();608- let (w, h) = (rgb_image.width() as usize, rgb_image.height() as usize);609-610- let encode_start = Instant::now();611- let rgb_source = RgbSliceU8::new(rgb_image.as_raw(), (w, h));612- let yuv = YUVBuffer::from_rgb8_source(rgb_source);613- let (h264_data, is_keyframe) = {614- let bitstream = encoder.encode(&yuv).context("H.264 encode failed")?;615- let kf = matches!(616- bitstream.frame_type(),617- openh264::encoder::FrameType::I | openh264::encoder::FrameType::IDR618- );619- (bitstream.to_vec(), kf)643+ let (w, h, h264_data, is_keyframe, capture_ms, encode_ms) = match rx.recv() {644+ Ok(Ok(frame)) => frame,645+ Ok(Err(e)) => return Err(e),646+ Err(_) => {647+ eprintln!("[host] capture thread ended");648+ break;649+ }620650 };621- let encode_ms = encode_start.elapsed().as_secs_f64() * 1000.0;622651 let h264_size = h264_data.len();623652 624653 let header = [@@ -664,5 +693,7 @@ async fn stream_frames_xcap(
664693 tokio::task::yield_now().await;665694 }666695 696+ drop(rx);697+ let _ = capture_thread.join();667698 Ok(())668699 }