### Install windows-capture using pip Source: https://github.com/niiightmarexd/windows-capture/blob/main/windows-capture-python/README.md Install the library from PyPI using pip. This is the standard method for adding the package to your Python environment. ```bash pip install windows-capture ``` -------------------------------- ### Basic Screen/Window Capture with Video Encoding Source: https://github.com/niiightmarexd/windows-capture/blob/main/README.md This snippet shows how to pick an item (window or screen) to capture, configure video encoding settings, and start the capture process. It handles frame arrival by sending frames to an encoder and stops the capture after a set duration. Requires `windows-windows-capture` crate. ```rust use std::io::{self, Write}; use std::time::Instant; use windows_capture::capture::{Context, GraphicsCaptureApiHandler}; use windows_capture::encoder::{ AudioSettingsBuilder, ContainerSettingsBuilder, VideoEncoder, VideoSettingsBuilder, }; use windows_capture::frame::Frame; use windows_capture::graphics_capture_api::InternalCaptureControl; use windows_capture::graphics_capture_picker::GraphicsCapturePicker; use windows_capture::settings::{ ColorFormat, CursorCaptureSettings, DirtyRegionSettings, DrawBorderSettings, MinimumUpdateIntervalSettings, SecondaryWindowSettings, Settings, }; // Handles capture events. struct Capture { // The video encoder that will be used to encode the frames. encoder: Option, // To measure the time the capture has been running start: Instant, } impl GraphicsCaptureApiHandler for Capture { // The type of flags used to get the values from the settings, here they are the width and height. type Flags = (i32, i32); // The type of error that can be returned from `CaptureControl` and `start` // functions. type Error = Box; // Function that will be called to create a new instance. The flags can be // passed from settings. fn new(ctx: Context) -> Result { // If we didn't want to get the size from the settings, we could use frame.width() and frame.height() // in the on_frame_arrived function, but we would need to create the encoder there. let encoder = VideoEncoder::new( VideoSettingsBuilder::new(ctx.flags.0 as u32, ctx.flags.1 as u32), AudioSettingsBuilder::default().disabled(true), ContainerSettingsBuilder::default(), "video.mp4", )?; Ok(Self { encoder: Some(encoder), start: Instant::now() }) } // Called every time a new frame is available. fn on_frame_arrived( &mut self, frame: &mut Frame, capture_control: InternalCaptureControl, ) -> Result<(), Self::Error> { print!("\rRecording for: {} seconds", self.start.elapsed().as_secs()); io::stdout().flush()?; // Send the frame to the video encoder self.encoder.as_mut().unwrap().send_frame(frame)?; // The frame has other uses too, for example, you can save a single frame // to a file, like this: frame.save_as_image("frame.png", ImageFormat::Png)?; // Or get the raw data like this so you have full control: let data = frame.buffer()?; // Stop the capture after 6 seconds if self.start.elapsed().as_secs() >= 6 { // Finish the encoder and save the video. self.encoder.take().unwrap().finish()?; capture_control.stop(); // Because the previous prints did not include a newline. println!(); } Ok(()) } // Optional handler called when the capture item (usually a window) is closed. fn on_closed(&mut self) -> Result<(), Self::Error> { println!("Capture session ended"); Ok(()) } } fn main() { // Opens a dialog to pick a window or screen to capture; refer to the docs for other capture items. let item = GraphicsCapturePicker::pick_item().expect("Failed to pick item"); // If the user canceled the selection, exit. let Some(item) = item else { println!("No item selected"); return; }; // Get the size of the item to pass to the settings. let size = item.size().expect("Failed to get item size"); let settings = Settings::new( // Item to capture item, // Capture cursor settings CursorCaptureSettings::Default, // Draw border settings DrawBorderSettings::Default, // Secondary window settings, if you want to include secondary windows in the capture SecondaryWindowSettings::Default, // Minimum update interval, if you want to change the frame rate limit (default is 60 FPS or 16.67 ms) MinimumUpdateIntervalSettings::Default, // Dirty region settings DirtyRegionSettings::Default, // The desired color format for the captured frame. ColorFormat::Rgba8, // Additional flags for the capture settings that will be passed to the user-defined `new` function. size, ); // Starts the capture and takes control of the current thread. // The errors from the handler trait will end up here. Capture::start(settings).expect("Screen capture failed"); } ``` -------------------------------- ### Stream-based Video Encoding Example Source: https://github.com/niiightmarexd/windows-capture/blob/main/README.md This Rust code demonstrates capturing screen content and encoding it into an in-memory stream using `VideoEncoder::new_from_stream`. It's suitable for scenarios like network streaming or piping to other processes. The example captures for 6 seconds and then saves the stream to 'stream_output.mp4'. ```rust use std::io::{self, Write}; use std::time::Instant; use windows::Storage::Streams::InMemoryRandomAccessStream; use windows::core::Interface; use windows_capture::capture::{Context, GraphicsCaptureApiHandler}; use windows_capture::encoder::{AudioSettingsBuilder, ContainerSettingsBuilder, VideoEncoder, VideoSettingsBuilder}; use windows_capture::frame::Frame; use windows_capture::graphics_capture_api::InternalCaptureControl; use windows_capture::graphics_capture_picker::GraphicsCapturePicker; use windows_capture::settings::{ ColorFormat, CursorCaptureSettings, DirtyRegionSettings, DrawBorderSettings, MinimumUpdateIntervalSettings, SecondaryWindowSettings, Settings, }; struct StreamCapture { encoder: Option, stream: InMemoryRandomAccessStream, start: Instant, } impl GraphicsCaptureApiHandler for StreamCapture { type Flags = (i32, i32); type Error = Box; fn new(ctx: Context) -> Result { // Create an in-memory stream that the encoder will write into. // This is useful for scenarios where you want to process the encoded // video in memory (e.g., sending it over a network, piping to another // process, or performing further transformations) instead of writing // directly to a file. let stream = InMemoryRandomAccessStream::new()?; let encoder = VideoEncoder::new_from_stream( VideoSettingsBuilder::new(ctx.flags.0 as u32, ctx.flags.1 as u32), AudioSettingsBuilder::default().disabled(true), ContainerSettingsBuilder::default(), stream.cast()?, )?; Ok(Self { encoder: Some(encoder), stream, start: Instant::now() }) } fn on_frame_arrived( &mut self, frame: &mut Frame, capture_control: InternalCaptureControl, ) -> Result<(), Self::Error> { print!( "\rStreaming for: {} seconds | Buffer size: {} bytes", self.start.elapsed().as_secs(), self.stream.Size()? ); io::stdout().flush()?; self.encoder.as_mut().unwrap().send_frame(frame)?; // Stop after 6 seconds and dump the in-memory buffer to a file to prove // the stream-based encoder works. In a real application you would read // from the stream continuously and forward the bytes elsewhere. if self.start.elapsed().as_secs() >= 6 { self.encoder.take().unwrap().finish()?; let size = self.stream.Size()?; println!("\nCapture finished. Stream contains {size} bytes."); // Write the in-memory stream to a file as a demonstration. let reader = windows::Storage::Streams::DataReader::CreateDataReader(&self.stream.GetInputStreamAt(0)?)?; reader.LoadAsync(size as u32)?.join()?; let mut bytes = vec![0u8; size as usize]; reader.ReadBytes(&mut bytes)?; std::fs::write("stream_output.mp4", &bytes)?; println!("Saved stream to stream_output.mp4"); capture_control.stop(); } Ok(()) } fn on_closed(&mut self) -> Result<(), Self::Error> { println!("Capture session ended"); Ok(()) } } fn main() { let item = GraphicsCapturePicker::pick_item().expect("Failed to pick item"); let Some(item) = item else { println!("No item selected"); return; }; let size = item.size().expect("Failed to get item size"); let settings = Settings::new( item, CursorCaptureSettings::Default, DrawBorderSettings::Default, SecondaryWindowSettings::Default, MinimumUpdateIntervalSettings::Default, DirtyRegionSettings::Default, ColorFormat::Rgba8, size, ); StreamCapture::start(settings).expect("Stream capture failed"); } ``` -------------------------------- ### Capture Primary Monitor with DXGI Source: https://github.com/niiightmarexd/windows-capture/blob/main/README.md This snippet captures the primary monitor's screen and saves it as a PNG. It uses `DxgiDuplicationApi` to create a duplication session and `acquire_next_frame` to get a frame. Ensure the `windows-capture` crate is added as a dependency. ```rust use windows_capture::dxgi_duplication_api::DxgiDuplicationApi; use windows_capture::encoder::ImageFormat; use windows_capture::monitor::Monitor; fn main() -> Result<(), Box> { // Select a monitor (primary in this example) let monitor = Monitor::primary()?; // Create a duplication session for this monitor let mut dup = DxgiDuplicationApi::new(monitor)?; // Try to grab one frame within ~33ms (about 30 FPS budget) let mut frame = dup.acquire_next_frame(33)?; // Map the GPU image into CPU memory and save a PNG // Note: The API could send an empty frame especially // in the first few calls, you can check this by seeing if // frame.frame_info().LastPresentTime is zero. frame.save_as_image("dxgi_screenshot.png", ImageFormat::Png)?; Ok(()) } ``` -------------------------------- ### Basic Graphics Capture API Usage Source: https://github.com/niiightmarexd/windows-capture/blob/main/windows-capture-python/README.md Demonstrates how to initialize and use the WindowsCapture class to capture frames. Includes event handlers for frame arrival and session closure. Frames can be saved as images, and the capture can be stopped gracefully. ```python from windows_capture import WindowsCapture, Frame, InternalCaptureControl # Any error from on_closed and on_frame_arrived will surface here capture = WindowsCapture( cursor_capture=None, draw_border=None, monitor_index=None, window_name=None, ) # Called every time a new frame is available @capture.event def on_frame_arrived(frame: Frame, capture_control: InternalCaptureControl): print("New frame arrived") # Save the frame as an image to the specified path frame.save_as_image("image.png") # Gracefully stop the capture thread capture_control.stop() # Called when the capture item closes (usually when the window closes). # The capture session will end after this function returns. @capture.event def on_closed(): print("Capture session closed") capture.start() ``` -------------------------------- ### DXGI Desktop Duplication API Usage Source: https://github.com/niiightmarexd/windows-capture/blob/main/windows-capture-python/README.md Shows how to create and use a DxgiDuplicationSession to capture frames from the primary monitor. Includes methods for acquiring frames, converting them to NumPy arrays, saving them as images, and handling DXGI access loss by recreating the session. ```python from windows_capture import DxgiDuplicationSession # Create a duplication session for the primary monitor session = DxgiDuplicationSession() # Grab a frame (returns None if no frame is available within the timeout) frame = session.acquire_frame(timeout_ms=33) if frame is not None: image = frame.to_numpy(copy=False) # shape: (height, width, 4) # Save as PNG using OpenCV frame.save_as_image("duplication.png") # Recreate the session if DXGI reports access loss try: session.acquire_frame() except RuntimeError: session.recreate() ``` -------------------------------- ### Add windows-capture Dependency using Cargo Command Source: https://github.com/niiightmarexd/windows-capture/blob/main/README.md Alternatively, add the windows-capture crate as a dependency using the cargo add command. ```bash cargo add windows-capture ``` -------------------------------- ### Add windows-capture Dependency to Cargo.toml Source: https://github.com/niiightmarexd/windows-capture/blob/main/README.md Add the windows-capture crate as a dependency in your project's Cargo.toml file. ```toml [dependencies] windows-capture = "2.0.0" ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.