Last active
July 12, 2022 10:33
-
-
Save jakobrs/78687f41e365da9ea3a0e23a0b4db693 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use gstreamer as gst; | |
use gstreamer_app as gst_app; | |
use gstreamer_video as gst_video; | |
use anyhow::Result; | |
use byte_slice_cast::*; | |
use gst::prelude::*; | |
use portal_screencast::ScreenCast; | |
fn main() -> Result<()> { | |
env_logger::init(); | |
let screencast = ScreenCast::new()?.start(None)?; | |
let fd = screencast.pipewire_fd(); | |
let stream = screencast.streams().next().expect("No stream"); | |
let node = stream.pipewire_node(); | |
log::info!("Pipewire screencast session set up with fd={fd} node={node}"); | |
gst::init()?; | |
let pipeline = gst::Pipeline::new(None); | |
let pipewiresrc = | |
gst::ElementFactory::make_with_properties("pipewiresrc", &[("fd", &fd), ("path", &node)])?; | |
let appsink = gst::ElementFactory::make("appsink", None)?; | |
pipeline.add_many(&[&pipewiresrc, &appsink])?; | |
pipewiresrc.link(&appsink)?; | |
let appsink = appsink | |
.dynamic_cast::<gst_app::AppSink>() | |
.map_err(|_| anyhow::anyhow!("Failed to perform dynamic cast"))?; | |
appsink.set_caps(Some( | |
&gst::Caps::builder("video/x-raw") | |
.field("format", "RGBx") // this seems to be the default and is the only format that works | |
.build(), | |
)); | |
appsink.set_callbacks( | |
gst_app::AppSinkCallbacks::builder() | |
.new_sample(|appsink| { | |
let sample = appsink.pull_sample().map_err(|_| gst::FlowError::Eos)?; | |
let buffer = sample.buffer().expect("Getting buffer"); // TODO: errors | |
let map = buffer.map_readable().expect("Mapping"); | |
let samples = map.as_slice_of::<u32>().expect("Reinterpreting samples"); | |
log::info!("First 10 pixels: {:x?}", &samples[..10]); | |
Ok(gst::FlowSuccess::Ok) | |
}) | |
.build(), | |
); | |
// don't really know how this works | |
// pieced together from random bits of documentation and this | |
// StackOveflow answer: https://stackoverflow.com/a/55516750 | |
let pad = pipewiresrc | |
.static_pad("src") | |
.ok_or_else(|| anyhow::anyhow!("Unable to get pad thingy"))?; | |
pad.add_probe(gst::PadProbeType::EVENT_BOTH, |_, info| { | |
if let Some(gst::PadProbeData::Event(ev)) = &info.data { | |
match ev.view() { | |
gst::EventView::Caps(caps) => { | |
log::info!("caps: {:?}", caps.caps()); | |
} | |
_ => (), | |
} | |
} | |
gst::PadProbeReturn::Ok | |
}) | |
.ok_or_else(|| anyhow::anyhow!("Unable to add probe"))?; | |
log::info!("Setting state to PLAYING"); | |
pipeline.set_state(gst::State::Playing)?; | |
log::info!("Set state to PLAYING"); | |
let bus = pipeline.bus().unwrap(); | |
for msg in bus.iter_timed(gst::ClockTime::NONE) { | |
use gst::MessageView; | |
log::debug!("{msg:?}"); | |
match msg.view() { | |
MessageView::Eos(..) => break, | |
MessageView::Error(err) => { | |
println!( | |
"Error from {:?}: {} ({:?})", | |
err.src().map(|s| s.path_string()), | |
err.error(), | |
err.debug() | |
); | |
break; | |
} | |
_ => (), | |
} | |
} | |
pipeline.set_state(gst::State::Null)?; | |
Ok(()) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment