#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum ShowMode {
Video = 0,
Waves = 1,
Rdft = 2,
}
impl ShowMode {
pub fn as_u8(self) -> u8 {
self as u8
}
pub fn as_str(self) -> &'static str {
match self {
Self::Video => "video",
Self::Waves => "waves",
Self::Rdft => "rdft",
}
}
}
impl Default for ShowMode {
fn default() -> Self {
Self::Video
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum KeyBinding {
Q,
Esc,
F,
P,
Space,
M,
Nine,
Zero,
Slash,
Asterisk,
A,
V,
T,
C,
W,
S,
Left,
Right,
Down,
Up,
PageDown,
PageUp,
}
impl KeyBinding {
pub fn description(self) -> &'static str {
match self {
Self::Q | Self::Esc => "Quit",
Self::F => "Toggle fullscreen",
Self::P | Self::Space => "Pause/Resume",
Self::M => "Toggle mute",
Self::Nine | Self::Slash => "Decrease volume",
Self::Zero | Self::Asterisk => "Increase volume",
Self::A => "Cycle audio channel",
Self::V => "Cycle video channel",
Self::T => "Cycle subtitle channel",
Self::C => "Cycle program",
Self::W => "Cycle video filters or show modes",
Self::S => "Step to next frame",
Self::Left => "Seek backward 10 seconds",
Self::Right => "Seek forward 10 seconds",
Self::Down => "Seek backward 1 minute",
Self::Up => "Seek forward 1 minute",
Self::PageDown => "Seek to previous chapter or -10 minutes",
Self::PageUp => "Seek to next chapter or +10 minutes",
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MouseAction {
RightClick,
LeftDoubleClick,
}
impl MouseAction {
pub fn description(self) -> &'static str {
match self {
Self::RightClick => "Seek to percentage in file",
Self::LeftDoubleClick => "Toggle fullscreen",
}
}
}
#[derive(Debug, Clone, Default)]
pub struct WindowState {
pub width: Option<u32>,
pub height: Option<u32>,
pub x: Option<i32>,
pub y: Option<i32>,
pub fullscreen: bool,
pub title: Option<String>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum PlaybackState {
Playing,
Paused,
Stopped,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VisualizationType {
None,
Waveform,
Spectrum,
}
impl From<ShowMode> for VisualizationType {
fn from(mode: ShowMode) -> Self {
match mode {
ShowMode::Video => Self::None,
ShowMode::Waves => Self::Waveform,
ShowMode::Rdft => Self::Spectrum,
}
}
}
#[derive(Debug, Clone)]
pub struct HwAccelOptions {
pub enabled: bool,
pub method: Option<String>,
pub device: Option<String>,
}
impl Default for HwAccelOptions {
fn default() -> Self {
Self {
enabled: false,
method: None,
device: None,
}
}
}
impl HwAccelOptions {
pub fn new() -> Self {
Self::default()
}
pub fn enable(mut self) -> Self {
self.enabled = true;
self
}
pub fn method(mut self, method: impl Into<String>) -> Self {
self.method = Some(method.into());
self.enabled = true;
self
}
pub fn device(mut self, device: impl Into<String>) -> Self {
self.device = Some(device.into());
self
}
#[cfg(target_os = "linux")]
pub fn vaapi() -> Self {
Self::new().method("vaapi")
}
#[cfg(target_os = "linux")]
pub fn vdpau() -> Self {
Self::new().method("vdpau")
}
#[cfg(target_os = "macos")]
pub fn videotoolbox() -> Self {
Self::new().method("videotoolbox")
}
#[cfg(target_os = "windows")]
pub fn dxva2() -> Self {
Self::new().method("dxva2")
}
#[cfg(target_os = "windows")]
pub fn d3d11va() -> Self {
Self::new().method("d3d11va")
}
pub fn cuda() -> Self {
Self::new().method("cuda")
}
pub fn qsv() -> Self {
Self::new().method("qsv")
}
}
#[derive(Debug, Clone, Default)]
pub struct VulkanOptions {
pub enabled: bool,
pub params: Vec<(String, String)>,
}
impl VulkanOptions {
pub fn new() -> Self {
Self::default()
}
pub fn enable(mut self) -> Self {
self.enabled = true;
self
}
pub fn param(mut self, key: impl Into<String>, value: impl Into<String>) -> Self {
self.params.push((key.into(), value.into()));
self.enabled = true;
self
}
pub fn build_params(&self) -> Option<String> {
if self.params.is_empty() {
None
} else {
Some(
self.params
.iter()
.map(|(k, v)| format!("{}={}", k, v))
.collect::<Vec<_>>()
.join(":")
)
}
}
}
#[derive(Debug, Clone, Default)]
pub struct InputStats {
pub duration: Option<f64>,
pub codec_params: Option<String>,
pub position: Option<f64>,
pub av_sync_drift: Option<f64>,
}
pub fn get_key_bindings() -> Vec<(String, String)> {
vec![
("q, ESC".to_string(), "Quit".to_string()),
("f".to_string(), "Toggle full screen".to_string()),
("p, SPC".to_string(), "Pause".to_string()),
("m".to_string(), "Toggle mute".to_string()),
("9, 0".to_string(), "Decrease/increase volume".to_string()),
("/, *".to_string(), "Decrease/increase volume".to_string()),
("a".to_string(), "Cycle audio channel".to_string()),
("v".to_string(), "Cycle video channel".to_string()),
("t".to_string(), "Cycle subtitle channel".to_string()),
("c".to_string(), "Cycle program".to_string()),
("w".to_string(), "Cycle video filters or show modes".to_string()),
("s".to_string(), "Step to next frame".to_string()),
("left/right".to_string(), "Seek backward/forward 10 seconds".to_string()),
("down/up".to_string(), "Seek backward/forward 1 minute".to_string()),
("page down/up".to_string(), "Seek to previous/next chapter or ±10 min".to_string()),
("mouse right click".to_string(), "Seek to percentage in file".to_string()),
("mouse left double-click".to_string(), "Toggle full screen".to_string()),
]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_show_mode() {
assert_eq!(ShowMode::Video.as_u8(), 0);
assert_eq!(ShowMode::Waves.as_u8(), 1);
assert_eq!(ShowMode::Rdft.as_u8(), 2);
assert_eq!(ShowMode::Video.as_str(), "video");
assert_eq!(ShowMode::default(), ShowMode::Video);
}
#[test]
fn test_key_binding_description() {
assert_eq!(KeyBinding::Q.description(), "Quit");
assert_eq!(KeyBinding::F.description(), "Toggle fullscreen");
assert_eq!(KeyBinding::Left.description(), "Seek backward 10 seconds");
}
#[test]
fn test_visualization_type() {
assert_eq!(VisualizationType::from(ShowMode::Video), VisualizationType::None);
assert_eq!(VisualizationType::from(ShowMode::Waves), VisualizationType::Waveform);
assert_eq!(VisualizationType::from(ShowMode::Rdft), VisualizationType::Spectrum);
}
#[test]
fn test_hwaccel_options() {
let cuda = HwAccelOptions::cuda();
assert!(cuda.enabled);
assert_eq!(cuda.method, Some("cuda".to_string()));
let custom = HwAccelOptions::new()
.method("vaapi")
.device("/dev/dri/renderD128");
assert!(custom.enabled);
assert_eq!(custom.method, Some("vaapi".to_string()));
assert_eq!(custom.device, Some("/dev/dri/renderD128".to_string()));
}
#[test]
fn test_vulkan_options() {
let vulkan = VulkanOptions::new()
.enable()
.param("device_index", "0")
.param("queue_count", "4");
assert!(vulkan.enabled);
assert_eq!(vulkan.build_params(), Some("device_index=0:queue_count=4".to_string()));
}
}