Allow config to be updated with CLI args

This commit is contained in:
Josh Megnauth 2024-02-15 23:38:23 -05:00
parent 99595eeeed
commit 028fd83296
No known key found for this signature in database
GPG key ID: 70813183462EFAD3
3 changed files with 120 additions and 15 deletions

View file

@ -4,7 +4,9 @@ use cosmic::{
cosmic_config::{self, cosmic_config_derive::CosmicConfigEntry, CosmicConfigEntry},
theme,
};
use lexopt::prelude::*;
use serde::{Deserialize, Serialize};
use std::{path::PathBuf, process};
use crate::wrappers::HWDeviceType;
@ -41,3 +43,52 @@ impl Default for Config {
}
}
}
impl Config {
pub fn with_args(&mut self, args: &mut Args) {
if let Some(decoder) = args.decoder {
self.hw_decoder = decoder;
}
}
}
pub struct Args {
pub paths: Vec<PathBuf>,
pub decoder: Option<HWDeviceType>,
}
impl Args {
pub fn parse_args() -> Result<Self, lexopt::Error> {
let mut paths = Vec::new();
let mut decoder = None;
let mut parser = lexopt::Parser::from_env();
while let Some(arg) = parser.next()? {
match arg {
Long("list-hwdec") => {
println!("Supported hardware decoders:");
for hwdec in HWDeviceType::supported_devices() {
println!("\t* [{}] {hwdec}", hwdec.short_name());
}
process::exit(0);
}
Long("hwdec") => {
decoder = Some(parser.value()?.parse()?);
}
Value(path) => {
let path = path.parse()?;
paths.push(path);
}
_ => return Err(arg.unexpected()),
}
}
if paths.is_empty() {
return Err(lexopt::Error::MissingValue {
option: Some("missing video path".into()),
});
}
Ok(Self { paths, decoder })
}
}

View file

@ -16,14 +16,12 @@ use cosmic::{
use std::{
any::TypeId,
collections::HashMap,
env,
path::PathBuf,
process,
env, process,
sync::{mpsc, Arc, Mutex},
time::{Duration, Instant},
};
use config::{AppTheme, Config, CONFIG_VERSION};
use config::{AppTheme, Args, Config, CONFIG_VERSION};
mod config;
use key_bind::{key_binds, KeyBind};
@ -42,16 +40,26 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
env_logger::Builder::from_env(env_logger::Env::default().default_filter_or("warn")).init();
localize::localize();
let mut args = match Args::parse_args() {
Ok(args) => args,
Err(e) => {
log::error!("{e}");
process::exit(1);
}
};
let (config_handler, config) = match cosmic_config::Config::new(App::APP_ID, CONFIG_VERSION) {
Ok(config_handler) => {
let config = match Config::get_entry(&config_handler) {
let mut config = match Config::get_entry(&config_handler) {
Ok(ok) => ok,
Err((errs, config)) => {
log::info!("errors loading config: {:?}", errs);
config
}
};
// Update config with command line args
config.with_args(&mut args);
(Some(config_handler), config)
}
Err(err) => {
@ -60,14 +68,9 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
}
};
//TODO: support multiple paths
let path = match env::args().skip(1).next() {
Some(arg) => PathBuf::from(arg),
None => {
log::error!("no argument provided");
process::exit(1);
}
};
//TODO: support using multiple paths
let Args { mut paths, .. } = args;
let path = paths.pop().unwrap();
let (player_tx, video_queue_lock) = player::run(path);

View file

@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-only
use std::str::FromStr;
use std::{fmt, iter::FusedIterator, str::FromStr};
use ffmpeg_next::ffi::{av_hwdevice_iterate_types, AVHWDeviceType};
use serde::{
@ -25,6 +25,8 @@ pub enum HWDeviceType {
/// DirectX Video Acceleration 2.0
/// https://learn.microsoft.com/en-us/windows/win32/medfound/about-dxva-2-0
Dxva2,
/// Direct Rendering Manager
/// https://dri.freedesktop.org/wiki/DRM/
Drm,
/// MediaCodec
/// Android only
@ -70,7 +72,26 @@ impl HWDeviceType {
}
}
/// Supported hardware decoders
/// Short name for CLI arguments
pub const fn short_name(self) -> &'static str {
match self {
Self::None => "none",
Self::Cuda => "cuda",
Self::Dxva2 => "dxva2",
Self::D3d11va => "d3d11va",
Self::D3d12va => "d3d12va",
Self::Drm => "drm",
Self::MediaCodec => "mediacodec",
Self::OpenCl => "opencl",
Self::Qsv => "qsv",
Self::Vaapi => "vaapi",
Self::Vdpau => "vdpau",
Self::VideoToolbox => "videotoolbox",
Self::Vulkan => "vulkan",
}
}
/// System's supported hardware decoders
pub fn supported_devices() -> SupportedDeviceIter {
SupportedDeviceIter::default()
}
@ -104,6 +125,12 @@ impl FromStr for HWDeviceType {
}
}
impl fmt::Display for HWDeviceType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.name())
}
}
impl From<AVHWDeviceType> for HWDeviceType {
fn from(value: AVHWDeviceType) -> Self {
match value {
@ -131,6 +158,7 @@ impl Default for HWDeviceType {
}
}
/// Iterator over system's supported hardware decoders.
pub struct SupportedDeviceIter {
current: AVHWDeviceType,
}
@ -147,13 +175,36 @@ impl Iterator for SupportedDeviceIter {
type Item = HWDeviceType;
fn next(&mut self) -> Option<Self::Item> {
// None is a sentinel value that indicates the iterator is exhausted
if self.current == AVHWDeviceType::AV_HWDEVICE_TYPE_NONE {
None
} else {
let prev = self.current;
// SAFETY: The docs and examples state that the iterator yields the next value
// when the previous is passed in.
self.current = unsafe { av_hwdevice_iterate_types(prev) };
Some(prev.into())
}
}
}
impl FusedIterator for SupportedDeviceIter {}
#[cfg(test)]
mod tests {
use std::hint::black_box;
use super::*;
// The iterator's yielded values aren't important since hardware decoders vary by system
// This is just a sanity check to ensure the iterator works
#[test]
fn supported_device_iter_doesnt_seg_fault() {
for decoder in HWDeviceType::supported_devices() {
black_box(decoder);
}
let _decoders: Vec<_> = black_box(HWDeviceType::supported_devices().collect());
}
}