Skip to content

Commit 8638c8a

Browse files
committed
feat: specifying vaapi device path (#21)
allows specifying the vaapi device path for AMD/Intel GPUs via --vaapi-device CLI arg or VERTD_VAAPI_DEVICE_PATH env variable fixes #21
1 parent 0ffb7d5 commit 8638c8a

7 files changed

Lines changed: 93 additions & 30 deletions

File tree

src/converter/gpu.rs

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,21 +49,31 @@ impl ConverterGPU {
4949
}
5050
}
5151

52-
pub fn hwaccel_args(&self) -> &[&str] {
52+
#[allow(unused_variables)]
53+
pub fn hwaccel_args(&self, vaapi_device_path: Option<&str>) -> Vec<String> {
5354
#[cfg(target_os = "linux")]
5455
match self {
55-
ConverterGPU::NVIDIA => &["-hwaccel", "cuda"],
56-
ConverterGPU::Apple => &["-hwaccel", "videotoolbox"],
57-
ConverterGPU::AMD => &["-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi"],
58-
ConverterGPU::Intel => &["-hwaccel", "vaapi", "-hwaccel_output_format", "vaapi"],
56+
ConverterGPU::NVIDIA => vec!["-hwaccel".to_string(), "cuda".to_string()],
57+
ConverterGPU::Apple => vec!["-hwaccel".to_string(), "videotoolbox".to_string()],
58+
ConverterGPU::AMD | ConverterGPU::Intel => {
59+
let mut args = vec!["-hwaccel".to_string(), "vaapi".to_string()];
60+
61+
let device_path = vaapi_device_path.unwrap_or("/dev/dri/renderD128");
62+
63+
args.push("-vaapi_device".to_string());
64+
args.push(device_path.to_string());
65+
args.push("-hwaccel_output_format".to_string());
66+
args.push("vaapi".to_string());
67+
args
68+
}
5969
}
6070

6171
#[cfg(not(target_os = "linux"))]
6272
match self {
63-
ConverterGPU::NVIDIA => &["-hwaccel", "cuda"],
64-
ConverterGPU::Apple => &["-hwaccel", "videotoolbox"],
65-
ConverterGPU::AMD => &["-hwaccel", "amf"],
66-
ConverterGPU::Intel => &["-hwaccel", "qsv"],
73+
ConverterGPU::NVIDIA => vec!["-hwaccel".to_string(), "cuda".to_string()],
74+
ConverterGPU::Apple => vec!["-hwaccel".to_string(), "videotoolbox".to_string()],
75+
ConverterGPU::AMD => vec!["-hwaccel".to_string(), "amf".to_string()],
76+
ConverterGPU::Intel => vec!["-hwaccel".to_string(), "qsv".to_string()],
6777
}
6878
}
6979
}

src/converter/mod.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ impl Converter {
4141
&self,
4242
job: &mut Job,
4343
gpu: &gpu::ConverterGPU,
44+
vaapi_device_path: Option<&str>,
4445
) -> anyhow::Result<(mpsc::Receiver<ProgressUpdate>, tokio::process::Child)> {
4546
let (tx, rx) = mpsc::channel(1);
4647
let input_filename = format!("input/{}.{}", job.id, self.conversion.from.to_string());
@@ -49,14 +50,15 @@ impl Converter {
4950
// let bitrate = job.bitrate().await?;
5051
// let fps = job.fps().await?;
5152
// the above but we run in parallel
52-
let (gpu, (bitrate, fps)) = tokio::try_join!(gpu::get_gpu(), job.bitrate_and_fps())?;
53+
let (bitrate, fps) = job.bitrate_and_fps().await?;
5354
let args = self
5455
.conversion
5556
.to_args(&self.speed, gpu, bitrate, fps)
5657
.await?;
5758
let args = args.iter().map(|s| s.as_str()).collect::<Vec<&str>>();
5859
let args = args.as_slice();
59-
let gpu_args: &[&str] = gpu.hwaccel_args();
60+
let gpu_args = gpu.hwaccel_args(vaapi_device_path);
61+
let gpu_args_refs: Vec<&str> = gpu_args.iter().map(|s| s.as_str()).collect();
6062

6163
let metadata_args: &[&str] = if self.keep_metadata {
6264
&["-map_metadata", "0", "-map_chapters", "0"]
@@ -65,8 +67,8 @@ impl Converter {
6567
};
6668

6769
let command = &[
68-
&["-hide_banner", "-loglevel", "error", "-progress", "pipe:1"],
69-
gpu_args,
70+
&["-hide_banner", "-loglevel", "error", "-progress", "pipe:1"][..],
71+
&gpu_args_refs[..],
7072
&["-i", &input_filename],
7173
args,
7274
metadata_args,

src/http/services/download.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
use actix_web::{get, web, HttpResponse, Responder, ResponseError};
44
use tokio::fs;
5-
use uuid::Uuid;
65

76
use crate::{http::response::ApiResponse, state::APP_STATE};
87

src/http/services/keep.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
use actix_web::{
44
post,
5-
web::{self, Json},
5+
web::Json,
66
HttpResponse, Responder, ResponseError,
77
};
88
use discord_webhook2::{message, webhook::DiscordWebhook};

src/http/services/websocket.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -143,11 +143,13 @@ pub async fn websocket(req: HttpRequest, stream: web::Payload) -> Result<HttpRes
143143

144144
let converter = Converter::new(from, to, speed, keep_metadata);
145145

146-
let gpu = {
146+
let (gpu, vaapi_device_path) = {
147147
let app_state = APP_STATE.lock().await;
148-
app_state.gpu.ok_or_else(|| {
149-
"GPU not initialized, please restart vertd.".to_string()
150-
})
148+
let gpu = app_state
149+
.gpu
150+
.ok_or_else(|| "GPU not initialized, please restart vertd.".to_string());
151+
let device_path = app_state.vaapi_device_path.clone();
152+
(gpu, device_path)
151153
};
152154

153155
let gpu = match gpu {
@@ -159,7 +161,10 @@ pub async fn websocket(req: HttpRequest, stream: web::Payload) -> Result<HttpRes
159161
}
160162
};
161163

162-
let (mut rx, process) = match converter.convert(&mut job, &gpu).await {
164+
let (mut rx, process) = match converter
165+
.convert(&mut job, &gpu, vaapi_device_path.as_deref())
166+
.await
167+
{
163168
Ok((rx, process)) => (rx, process),
164169
Err(e) => {
165170
let message: String = Message::Error {

src/main.rs

Lines changed: 55 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,36 @@ fn get_forced_gpu() -> Option<ConverterGPU> {
9393
None
9494
}
9595

96+
fn get_vaapi_device_path() -> Option<String> {
97+
// cli argument (-vaapi-device <value>)
98+
let args: Vec<String> = env::args().collect();
99+
if let Some(vaapi_arg_pos) = args
100+
.iter()
101+
.position(|arg| arg == "-vaapi-device" || arg == "--vaapi-device")
102+
{
103+
if let Some(device_value) = args.get(vaapi_arg_pos + 1) {
104+
info!(
105+
"using VA-API device path from command line argument: {}",
106+
device_value
107+
);
108+
return Some(device_value.clone());
109+
} else {
110+
warn!("VA-API device path argument specified but no value provided");
111+
}
112+
}
113+
114+
// environment variable
115+
if let Ok(device_path) = env::var("VERTD_VAAPI_DEVICE_PATH") {
116+
info!(
117+
"using VA-API device path from environment variable VERTD_VAAPI_DEVICE_PATH: {}",
118+
device_path
119+
);
120+
return Some(device_path);
121+
}
122+
123+
None
124+
}
125+
96126
#[tokio::main]
97127
async fn main() -> anyhow::Result<()> {
98128
dotenv().ok();
@@ -125,17 +155,31 @@ async fn main() -> anyhow::Result<()> {
125155
None => get_gpu().await,
126156
};
127157

158+
// get VA-API device path from CLI or env var
159+
let vaapi_device_path = get_vaapi_device_path();
160+
128161
match &gpu {
129-
Ok(gpu) => info!(
130-
"detected a{} {} GPU -- if this isn't your vendor, open an issue.",
131-
match gpu {
132-
converter::gpu::ConverterGPU::AMD => "n",
133-
converter::gpu::ConverterGPU::Apple => "n",
134-
converter::gpu::ConverterGPU::Intel => "n",
135-
_ => "",
136-
},
137-
gpu
138-
),
162+
Ok(gpu) => {
163+
info!(
164+
"detected a{} {} GPU -- if this isn't your vendor, open an issue.",
165+
match gpu {
166+
ConverterGPU::AMD => "n",
167+
ConverterGPU::Apple => "n",
168+
ConverterGPU::Intel => "n",
169+
_ => "",
170+
},
171+
gpu
172+
);
173+
174+
#[cfg(target_os = "linux")]
175+
if matches!(gpu, ConverterGPU::AMD | ConverterGPU::Intel) {
176+
let device_path = vaapi_device_path
177+
.as_ref()
178+
.map(|s| s.as_str())
179+
.unwrap_or("/dev/dri/renderD128");
180+
info!("using VA-API device path: {}", device_path);
181+
}
182+
}
139183
Err(e) => {
140184
error!("failed to get GPU vendor: {}", e);
141185
error!("vertd will still work, but it's going to be incredibly slow. be warned!");
@@ -145,6 +189,7 @@ async fn main() -> anyhow::Result<()> {
145189
if let Ok(gpu) = gpu {
146190
let mut app_state = state::APP_STATE.lock().await;
147191
app_state.gpu = Some(gpu);
192+
app_state.vaapi_device_path = vaapi_device_path;
148193
}
149194

150195
// remove input/ and output/ recursively if they exist -- we don't care if this fails tho

src/state/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub struct AppState {
1010
pub jobs: HashMap<Uuid, Job>,
1111
pub active_processes: HashMap<Uuid, tokio::process::Child>,
1212
pub gpu: Option<ConverterGPU>,
13+
pub vaapi_device_path: Option<String>,
1314
}
1415

1516
impl AppState {
@@ -18,6 +19,7 @@ impl AppState {
1819
jobs: HashMap::new(),
1920
active_processes: HashMap::new(),
2021
gpu: None,
22+
vaapi_device_path: None,
2123
}
2224
}
2325
}

0 commit comments

Comments
 (0)