use crate::error::CaptureResult;
use crate::types::{CaptureRegion, DisplayInfo, RawImage};
pub trait ScreenCapture: Send + Sync {
fn get_displays(&self) -> CaptureResult<Vec<DisplayInfo>>;
fn capture_display(&self, display_index: usize) -> CaptureResult<RawImage>;
fn capture_region(&self, region: CaptureRegion) -> CaptureResult<RawImage>;
fn implementation_name(&self) -> String;
fn is_hardware_accelerated(&self) -> bool {
false
}
fn is_available(&self) -> bool {
true
}
fn capabilities(&self) -> CaptureCapabilities {
CaptureCapabilities::default()
}
}
#[derive(Debug, Clone, Default)]
pub struct CaptureCapabilities {
pub supports_cursor: bool,
pub supports_window_capture: bool,
pub supports_hdr: bool,
pub max_resolution: (u32, u32),
pub supports_multi_display: bool,
pub supports_gpu_acceleration: bool,
pub estimated_latency_ms: u32,
}
pub trait PixelFormatConverter {
fn convert_bgra_to_rgba(&self, data: &mut [u8]);
fn convert_bgr_to_rgb(&self, data: &mut [u8]);
fn convert_rgba_to_rgb(&self, src: &[u8], dst: &mut [u8]);
fn flip_vertical(&self, data: &mut [u8], width: u32, height: u32, bytes_per_pixel: u32);
}
pub struct DefaultPixelConverter;
impl PixelFormatConverter for DefaultPixelConverter {
fn convert_bgra_to_rgba(&self, data: &mut [u8]) {
for chunk in data.chunks_exact_mut(4) {
chunk.swap(0, 2); }
}
fn convert_bgr_to_rgb(&self, data: &mut [u8]) {
for chunk in data.chunks_exact_mut(3) {
chunk.swap(0, 2); }
}
fn convert_rgba_to_rgb(&self, src: &[u8], dst: &mut [u8]) {
let mut dst_idx = 0;
for chunk in src.chunks_exact(4) {
dst[dst_idx] = chunk[0]; dst[dst_idx + 1] = chunk[1]; dst[dst_idx + 2] = chunk[2]; dst_idx += 3;
}
}
fn flip_vertical(&self, data: &mut [u8], width: u32, height: u32, bytes_per_pixel: u32) {
let row_size = (width * bytes_per_pixel) as usize;
let mut temp_row = vec![0u8; row_size];
for y in 0..height / 2 {
let top_offset = (y * width * bytes_per_pixel) as usize;
let bottom_offset = ((height - 1 - y) * width * bytes_per_pixel) as usize;
temp_row.copy_from_slice(&data[top_offset..top_offset + row_size]);
data.copy_within(bottom_offset..bottom_offset + row_size, top_offset);
data[bottom_offset..bottom_offset + row_size].copy_from_slice(&temp_row);
}
}
}
#[cfg(feature = "simd")]
pub mod simd_converter {
use super::{PixelFormatConverter, DefaultPixelConverter};
pub struct SimdPixelConverter;
impl PixelFormatConverter for SimdPixelConverter {
#[cfg(target_arch = "x86_64")]
fn convert_bgra_to_rgba(&self, data: &mut [u8]) {
unsafe {
if is_x86_feature_detected!("avx2") {
convert_bgra_to_rgba_avx2(data);
} else if is_x86_feature_detected!("ssse3") {
convert_bgra_to_rgba_ssse3(data);
} else {
DefaultPixelConverter.convert_bgra_to_rgba(data);
}
}
}
#[cfg(not(target_arch = "x86_64"))]
fn convert_bgra_to_rgba(&self, data: &mut [u8]) {
DefaultPixelConverter.convert_bgra_to_rgba(data);
}
fn convert_bgr_to_rgb(&self, data: &mut [u8]) {
DefaultPixelConverter.convert_bgr_to_rgb(data);
}
fn convert_rgba_to_rgb(&self, src: &[u8], dst: &mut [u8]) {
DefaultPixelConverter.convert_rgba_to_rgb(src, dst);
}
fn flip_vertical(&self, data: &mut [u8], width: u32, height: u32, bytes_per_pixel: u32) {
DefaultPixelConverter.flip_vertical(data, width, height, bytes_per_pixel);
}
}
#[cfg(target_arch = "x86_64")]
unsafe fn convert_bgra_to_rgba_avx2(data: &mut [u8]) {
use std::arch::x86_64::*;
let shuffle_mask = _mm256_setr_epi8(
2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15,
2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15,
);
let len = data.len();
let simd_len = len & !31;
for i in (0..simd_len).step_by(32) {
let ptr = data.as_mut_ptr().add(i);
let pixels = _mm256_loadu_si256(ptr as *const __m256i);
let shuffled = _mm256_shuffle_epi8(pixels, shuffle_mask);
_mm256_storeu_si256(ptr as *mut __m256i, shuffled);
}
for i in (simd_len..len).step_by(4) {
data.swap(i, i + 2);
}
}
#[cfg(target_arch = "x86_64")]
unsafe fn convert_bgra_to_rgba_ssse3(data: &mut [u8]) {
use std::arch::x86_64::*;
let shuffle_mask = _mm_setr_epi8(
2, 1, 0, 3, 6, 5, 4, 7, 10, 9, 8, 11, 14, 13, 12, 15,
);
let len = data.len();
let simd_len = len & !15;
for i in (0..simd_len).step_by(16) {
let ptr = data.as_mut_ptr().add(i);
let pixels = _mm_loadu_si128(ptr as *const __m128i);
let shuffled = _mm_shuffle_epi8(pixels, shuffle_mask);
_mm_storeu_si128(ptr as *mut __m128i, shuffled);
}
for i in (simd_len..len).step_by(4) {
data.swap(i, i + 2);
}
}
}