feat: encoder presets for wivrn

This commit is contained in:
Gabriele Musco 2024-07-27 00:00:06 +02:00
parent 1e4648b021
commit c58d9560e7
6 changed files with 247 additions and 2 deletions

View file

@ -2,3 +2,4 @@ pub mod active_runtime_json;
pub mod monado_autorun;
pub mod openvrpaths_vrpath;
pub mod wivrn_config;
pub mod wivrn_encoder_presets;

View file

@ -95,7 +95,7 @@ pub struct WivrnConfEncoder {
pub group: Option<i32>,
/// contains unknown fields
#[serde(flatten)]
other: Map<String, Value>,
pub other: Map<String, Value>,
}
impl Default for WivrnConfEncoder {
@ -128,6 +128,7 @@ pub struct WivrnConfig {
pub scale: Option<[f32; 2]>,
#[serde(skip_serializing_if = "Option::is_none")]
pub bitrate: Option<u32>,
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub encoders: Vec<WivrnConfEncoder>,
#[serde(skip_serializing_if = "Option::is_none")]

View file

@ -0,0 +1,84 @@
use super::wivrn_config::{Codec, Encoder, WivrnConfEncoder};
use lazy_static::lazy_static;
fn wivrn_encoder_presets() -> Vec<(&'static str, &'static str, Vec<WivrnConfEncoder>)> {
vec![
(
"3x VAAPI",
"Use 3 hardware accelerated encoders using VAAPI and the H265 codec.",
vec![
WivrnConfEncoder {
encoder: Encoder::Vaapi,
width: Some(0.5),
height: Some(0.25),
offset_x: Some(0.0),
offset_y: Some(0.0),
group: Some(0),
codec: Codec::H265,
..Default::default()
},
WivrnConfEncoder {
encoder: Encoder::Vaapi,
width: Some(0.5),
height: Some(0.75),
offset_x: Some(0.0),
offset_y: Some(0.25),
group: Some(0),
codec: Codec::H265,
..Default::default()
},
WivrnConfEncoder {
encoder: Encoder::Vaapi,
width: Some(0.5),
height: Some(1.0),
offset_x: Some(0.5),
offset_y: Some(0.0),
group: Some(1),
codec: Codec::H265,
..Default::default()
},
],
),
(
"2x VAAPI + 1 Software",
"Use 2 hardware accelerated encoders using VAAPI and a third one using software encoding. The hardware encoders use the H265 codec, while the software encoder uses H264.",
vec![
WivrnConfEncoder {
encoder: Encoder::Vaapi,
width: Some(0.5),
height: Some(0.25),
offset_x: Some(0.0),
offset_y: Some(0.0),
group: Some(0),
codec: Codec::H265,
..Default::default()
},
WivrnConfEncoder {
encoder: Encoder::Vaapi,
width: Some(0.5),
height: Some(0.75),
offset_x: Some(0.0),
offset_y: Some(0.25),
group: Some(0),
codec: Codec::H265,
..Default::default()
},
WivrnConfEncoder {
encoder: Encoder::X264,
width: Some(0.5),
height: Some(1.0),
offset_x: Some(0.5),
offset_y: Some(0.0),
group: Some(1),
codec: Codec::H264,
..Default::default()
},
],
),
]
}
lazy_static! {
pub static ref WIVRN_ENCODER_PRESETS: Vec<(&'static str, &'static str, Vec<WivrnConfEncoder>)> =
wivrn_encoder_presets();
}

View file

@ -19,5 +19,6 @@ mod steamvr_calibration_box;
mod term_widget;
mod util;
mod wivrn_conf_editor;
pub mod wivrn_encoder_presets_win;
pub const SENDER_IO_ERR_MSG: &str = "relm4 sender i/o failed";

View file

@ -3,12 +3,18 @@ use super::{
WivrnEncoderModel, WivrnEncoderModelInit, WivrnEncoderModelOutMsg,
},
util::bits_from_mbits,
wivrn_encoder_presets_win::{
WivrnEncoderPresetsWin, WivrnEncoderPresetsWinMsg, WivrnEncoderPresetsWinOutMsg,
},
};
use crate::{
file_builders::wivrn_config::{dump_wivrn_config, get_wivrn_config, WivrnConfig},
file_builders::wivrn_config::{
dump_wivrn_config, get_wivrn_config, WivrnConfEncoder, WivrnConfig,
},
ui::{
preference_rows::{number_entry_row, spin_row, switch_row},
util::bits_to_mbits,
wivrn_encoder_presets_win::WivrnEncoderPresetsWinInit,
},
};
use adw::prelude::*;
@ -28,6 +34,8 @@ pub struct WivrnConfEditor {
pub scaley_row: Option<adw::SpinRow>,
#[tracker::do_not_track]
bitrate_row: Option<adw::EntryRow>,
#[tracker::do_not_track]
wivrn_encoder_presets_win: Option<Controller<WivrnEncoderPresetsWin>>,
}
#[derive(Debug)]
@ -37,6 +45,8 @@ pub enum WivrnConfEditorMsg {
AddEncoder,
DeleteEncoder(String),
TcpOnlyChanged(bool),
OpenEncoderPresetsWin,
SetEncoderPreset(Vec<WivrnConfEncoder>),
}
pub struct WivrnConfEditorInit {
@ -145,6 +155,13 @@ impl SimpleComponent for WivrnConfEditor {
set_title: "Encoders",
adw::ActionRow {
set_title: "Add encoder",
add_suffix: presets_btn = &gtk::Button {
set_valign: gtk::Align::Center,
set_label: "Use Preset",
connect_clicked[sender] => move |_| {
sender.input(Self::Input::OpenEncoderPresetsWin)
}
},
add_suffix: add_encoder_btn = &gtk::Button {
set_halign: gtk::Align::Center,
set_valign: gtk::Align::Center,
@ -170,6 +187,23 @@ impl SimpleComponent for WivrnConfEditor {
self.set_conf(get_wivrn_config());
self.win.as_ref().unwrap().present();
}
Self::Input::OpenEncoderPresetsWin => {
self.wivrn_encoder_presets_win
.as_ref()
.unwrap()
.sender()
.emit(WivrnEncoderPresetsWinMsg::Present);
}
Self::Input::SetEncoderPreset(preset) => {
self.encoder_models.as_mut().unwrap().guard().clear();
preset.iter().for_each(|enc| {
self.encoder_models.as_mut().unwrap().guard().push_back(
WivrnEncoderModelInit {
encoder_conf: Some(enc.clone()),
},
);
});
}
Self::Input::Save => {
let x = self.scalex_row.as_ref().unwrap().adjustment().value();
let y = self.scaley_row.as_ref().unwrap().adjustment().value();
@ -234,6 +268,7 @@ impl SimpleComponent for WivrnConfEditor {
scalex_row: None,
scaley_row: None,
bitrate_row: None,
wivrn_encoder_presets_win: None,
tracker: 0,
};
@ -258,6 +293,18 @@ impl SimpleComponent for WivrnConfEditor {
model.win = Some(widgets.win.clone());
model.wivrn_encoder_presets_win = Some(
WivrnEncoderPresetsWin::builder()
.launch(WivrnEncoderPresetsWinInit {
parent_win: widgets.win.clone().upcast(),
})
.forward(sender.input_sender(), move |msg| match msg {
WivrnEncoderPresetsWinOutMsg::Selected(preset) => {
Self::Input::SetEncoderPreset(preset)
}
}),
);
ComponentParts { model, widgets }
}
}

View file

@ -0,0 +1,111 @@
use adw::prelude::*;
use relm4::prelude::*;
use crate::file_builders::{
wivrn_config::WivrnConfEncoder, wivrn_encoder_presets::WIVRN_ENCODER_PRESETS,
};
use super::SENDER_IO_ERR_MSG;
#[tracker::track]
pub struct WivrnEncoderPresetsWin {
win: Option<adw::Window>,
}
#[derive(Debug)]
pub enum WivrnEncoderPresetsWinMsg {
Present,
Selected(Vec<WivrnConfEncoder>),
}
#[derive(Debug)]
pub enum WivrnEncoderPresetsWinOutMsg {
Selected(Vec<WivrnConfEncoder>),
}
pub struct WivrnEncoderPresetsWinInit {
pub parent_win: gtk::Window,
}
#[relm4::component(pub)]
impl SimpleComponent for WivrnEncoderPresetsWin {
type Init = WivrnEncoderPresetsWinInit;
type Input = WivrnEncoderPresetsWinMsg;
type Output = WivrnEncoderPresetsWinOutMsg;
view! {
#[name(win)]
adw::Window {
set_modal: true,
set_hide_on_close: true,
set_transient_for: Some(&init.parent_win),
set_title: Some("WiVRn Encoder Presets"),
set_default_height: 400,
set_default_width: 300,
adw::ToolbarView {
set_top_bar_style: adw::ToolbarStyle::Flat,
set_hexpand: true,
set_vexpand: true,
add_top_bar: top_bar = &adw::HeaderBar {
set_vexpand: false,
},
#[wrap(Some)]
set_content: prefpage = &adw::PreferencesPage {
set_title: "Encoder Presets",
add: prefgrp = &adw::PreferencesGroup {
}
}
},
}
}
fn update(&mut self, message: Self::Input, sender: ComponentSender<Self>) {
self.reset();
match message {
Self::Input::Present => {
self.win.as_ref().unwrap().present();
}
Self::Input::Selected(preset) => {
sender
.output(Self::Output::Selected(preset))
.expect(SENDER_IO_ERR_MSG);
self.win.as_ref().unwrap().close();
}
}
}
fn init(
init: Self::Init,
root: Self::Root,
sender: ComponentSender<Self>,
) -> ComponentParts<Self> {
let mut model = Self {
win: None,
tracker: 0,
};
let widgets = view_output!();
model.win = Some(widgets.win.clone());
WIVRN_ENCODER_PRESETS
.iter()
.for_each(|(name, desc, enc_preset)| {
let row = adw::ActionRow::builder()
.title(*name)
.subtitle_lines(0)
.subtitle(*desc)
.activatable(true)
.build();
let sndr = sender.clone();
row.connect_activated(move |_| {
sndr.input(Self::Input::Selected(enc_preset.clone()))
});
widgets.prefgrp.add(&row);
});
ComponentParts { model, widgets }
}
}