use serde::{Deserialize, Serialize};
#[cfg(feature = "audio")]
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AudioConfig {
pub device_id: Option<String>,
pub sample_rate: u32,
pub channels: u16,
pub bitrate: u32,
}
#[cfg(feature = "audio")]
impl Default for AudioConfig {
fn default() -> Self {
Self {
device_id: None,
sample_rate: 48000, channels: 2,
bitrate: 128_000,
}
}
}
#[cfg(feature = "audio")]
impl AudioConfig {
pub fn with_device(device_id: impl Into<String>) -> Self {
Self {
device_id: Some(device_id.into()),
..Default::default()
}
}
pub fn mono(mut self) -> Self {
self.channels = 1;
self
}
pub fn stereo(mut self) -> Self {
self.channels = 2;
self
}
pub fn with_bitrate(mut self, bitrate: u32) -> Self {
self.bitrate = bitrate;
self
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum RecordingQuality {
Low,
Medium,
#[default]
High,
Custom,
}
impl RecordingQuality {
pub fn bitrate(&self) -> u32 {
match self {
RecordingQuality::Low => 2_500_000, RecordingQuality::Medium => 5_000_000, RecordingQuality::High => 10_000_000, RecordingQuality::Custom => 5_000_000, }
}
pub fn resolution(&self) -> (u32, u32) {
match self {
RecordingQuality::Low => (1280, 720),
RecordingQuality::Medium => (1920, 1080),
RecordingQuality::High => (1920, 1080),
RecordingQuality::Custom => (1920, 1080),
}
}
pub fn fps(&self) -> f64 {
match self {
RecordingQuality::Low => 30.0,
RecordingQuality::Medium => 30.0,
RecordingQuality::High => 30.0, RecordingQuality::Custom => 30.0,
}
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RecordingConfig {
pub width: u32,
pub height: u32,
pub fps: f64,
pub bitrate: u32,
pub quality: RecordingQuality,
pub fast_start: bool,
pub title: Option<String>,
#[cfg(feature = "audio")]
pub audio: Option<AudioConfig>,
}
impl RecordingConfig {
pub fn new(width: u32, height: u32, fps: f64) -> Self {
Self {
width,
height,
fps,
bitrate: 5_000_000,
quality: RecordingQuality::Custom,
fast_start: true,
title: None,
#[cfg(feature = "audio")]
audio: None,
}
}
pub fn from_quality(quality: RecordingQuality) -> Self {
let (width, height) = quality.resolution();
Self {
width,
height,
fps: quality.fps(),
bitrate: quality.bitrate(),
quality,
fast_start: true,
title: None,
#[cfg(feature = "audio")]
audio: None,
}
}
pub fn from_quality_with_fps(quality: RecordingQuality, fps: f64) -> Self {
let (width, height) = quality.resolution();
Self {
width,
height,
fps,
bitrate: quality.bitrate(),
quality,
fast_start: true,
title: None,
#[cfg(feature = "audio")]
audio: None,
}
}
pub fn with_title(mut self, title: impl Into<String>) -> Self {
self.title = Some(title.into());
self
}
pub fn with_fast_start(mut self, enabled: bool) -> Self {
self.fast_start = enabled;
self
}
pub fn with_bitrate(mut self, bitrate: u32) -> Self {
self.bitrate = bitrate;
self
}
#[cfg(feature = "audio")]
pub fn with_audio(mut self, audio_config: AudioConfig) -> Self {
self.audio = Some(audio_config);
self
}
#[cfg(feature = "audio")]
pub fn with_default_audio(mut self) -> Self {
self.audio = Some(AudioConfig::default());
self
}
}
impl Default for RecordingConfig {
fn default() -> Self {
Self::from_quality(RecordingQuality::High)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct RecordingStats {
pub video_frames: u64,
pub audio_frames: u64,
pub duration_secs: f64,
pub bytes_written: u64,
pub actual_fps: f64,
pub dropped_frames: u64,
pub output_path: String,
}
impl RecordingStats {
pub fn avg_bitrate(&self) -> f64 {
if self.duration_secs > 0.0 {
(self.bytes_written as f64 * 8.0) / self.duration_secs
} else {
0.0
}
}
}