Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ supported.
- **Intel Quick Sync Video H264/HEVC** (h264_qsv, hevc_qsv)
- ***Intel Arc AV1** (av1_qsv)
- **Apple Silicon H264/HEVC** (h264_videotoolbox, hevc_videotoolbox)
- ***VAAPI H264/HEVC/AV1 on Linux** (h264_vaapi, hevc_vaapi, av1_vaapi; commonly used with AMD or Intel GPUs)

The following have code in the project to 'support it' but currently <i>do not</i> function correctly:

Expand Down Expand Up @@ -114,6 +115,10 @@ it's highly suggested to use the same version, or at least version `6.*` of ffmp
- For Mac, recommended to install via `brew install ffmpeg` (will install ffpmpeg and ffprobe)
- For Linux, recommended to install using your distro's package manager. Note: the default one may be a much lower
version than `6.0` and may require more setup
- To use VAAPI on Linux, install the VAAPI driver package supplied by your distribution for your GPU vendor. For
example, AMD commonly uses the Mesa VAAPI driver, while current Intel hardware uses `intel-media-driver` (iHD)
and older Intel hardware may require the legacy i965 driver
- Make sure your user can access the DRM render nodes under `/dev/dri`
2) <a href='https://www.7-zip.org/download.html'>7-Zip</a> to unzip any downloaded ffmpeg binaries
3) ffmpeg/ffprobe must be available on your path (tool will error out if it can't find
either); <a href='https://www.architectryan.com/2018/03/17/add-to-the-path-on-windows-10/'>quick path setup guide for
Expand Down Expand Up @@ -156,6 +161,36 @@ benchmark is as simple as:

Kill the tool at any time by hitting `ctrl-c` in the terminal/console where the tool is running.

### VAAPI on Linux

VAAPI encoders use a DRM render node instead of the numeric `--gpu` option used by NVENC and AMF. The default device is
`/dev/dri/renderD128`; select a different GPU with `--vaapi-device`:

`./benchmark -e h264_vaapi -s 1080-60.y4m --vaapi-device /dev/dri/renderD128`

On a mixed-GPU system, pass the render node belonging to the GPU you want to benchmark, for example
`/dev/dri/renderD129`. VAAPI render-node ordering is independent of the numeric `--gpu` option.

The user running the benchmark must have permission to access the render device. First inspect the selected render
node and its permissions:

`ls -l /dev/dri/renderD128`

If the device belongs to a non-root group such as `render` or `video`, add your user to that group—for example,
`sudo usermod -aG render $USER`—then log out and back in for the new group membership to take effect. If the device's
group is `root`, do not add your user to the `root` group; instead, change the device's group to one your user belongs
to, for example `sudo chgrp "$(id -gn)" /dev/dri/renderD128`. This change may be reset when the device or system restarts.
You can alternatively run the benchmark with `sudo`, but this is not recommended.

For 10-bit HEVC or AV1, add `--ten-bit`. Ten-bit H264 VAAPI is not supported by this tool.

VAAPI is separate from vendor-specific FFmpeg backends such as Intel QSV and Nvidia NVENC. Use `h264_vaapi`,
`hevc_vaapi`, or `av1_vaapi` to benchmark VAAPI through a DRM render node. AV1 encoding requires hardware and a VAAPI
driver that exposes AV1 encode support.

Before running, verify that the FFmpeg build exposes the requested `h264_vaapi`, `hevc_vaapi`, or `av1_vaapi` encoder
with `ffmpeg -encoders`, and inspect available render nodes with `ls /dev/dri/renderD*`.

### Understanding the results

You'll be given the maximum fps statistics possible at a given resolution, with those results logged out to a
Expand Down Expand Up @@ -398,4 +433,4 @@ An example of what the author did for the nvenc_h264 encoder:
<i>Error about unsupported feature</i>

If you are getting the following: `#![feature] may not be used on the stable release channel`, this should be fixable by
running `cargo clean`.
running `cargo clean`.
13 changes: 12 additions & 1 deletion benchmark/src/benchmark_cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use clap::Parser;

use cli::cli_util::{
are_all_source_files_present, error_with_ack, get_repo_url, standard_cli_check,
validate_vaapi_options,
};
use cli::supported::get_supported_inputs;

Expand All @@ -28,10 +29,13 @@ pub struct BenchmarkCli {
/// the GPU you wish to run the encode on; defaults to the first/only GPU found in your system
#[arg(short, long, default_value = "0")]
pub gpu: u8,
/// DRM render node used by VAAPI encoders
#[arg(long, value_name = "device", default_value = "/dev/dri/renderD128")]
pub vaapi_device: String,

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe should have changed gpu flag to be string and pass this value there? As other encoders have similar things under linux.

/// whether to run decode benchmark as well; defaults to off, as this will take up more storage space
#[arg(short, long)]
pub decode: bool,
/// adds in '-pix_fmt yuv420p10le' to force 10-bit encoding
/// forces 10-bit encoding; VAAPI HEVC uploads p010 hardware frames
#[arg(short, long)]
pub ten_bit: bool,
// this is an internal option not intended to be exposed to the end user
Expand All @@ -57,6 +61,7 @@ impl BenchmarkCli {
log_output_directory: String::from(""),
verbose: false,
gpu: 0,
vaapi_device: String::from("/dev/dri/renderD128"),
decode: false,
ten_bit: false,
was_ui_opened: false,
Expand All @@ -72,6 +77,12 @@ impl BenchmarkCli {
&self.files_directory,
self.was_ui_opened,
);
validate_vaapi_options(
&self.encoder,
&self.vaapi_device,
self.ten_bit,
self.was_ui_opened,
);

// if you did not provide a source file, we'll be running on all expected files
if self.source_file.is_empty() && !are_all_source_files_present(&self.files_directory) {
Expand Down
10 changes: 10 additions & 0 deletions benchmark/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use codecs::get_vendor_for_codec;
use codecs::nvenc::Nvenc;
use codecs::permute::Permute;
use codecs::qsv::QSV;
use codecs::vaapi::Vaapi;
use codecs::vendor::Vendor;
use engine::benchmark_engine::BenchmarkEngine;
use ffmpeg::metadata::MetaData;
Expand Down Expand Up @@ -67,6 +68,7 @@ fn benchmark() {
permutation.bitrate = bitrate;
permutation.encoder_settings = settings;
permutation.verbose = cli.verbose;
permutation.vaapi_device = cli.vaapi_device.clone();

// tell this encode run that we'll want to preserve the file output
if cli.decode {
Expand Down Expand Up @@ -282,6 +284,10 @@ fn get_benchmark_settings_for(cli: &BenchmarkCli) -> String {
apple_h264.get_benchmark_settings()
}
}
Vendor::Vaapi => {
let vaapi = Vaapi::new(&cli.encoder, cli.ten_bit);
vaapi.get_benchmark_settings()
}
Vendor::Unknown => {
// nothing to do here
String::from("")
Expand All @@ -294,6 +300,10 @@ fn get_bitrate_for(metadata: &MetaData, string: String) -> u32 {
return *Nvenc::get_resolution_to_bitrate_map(metadata.fps)
.get(&metadata.get_res())
.unwrap();
} else if string.contains("vaapi") {
return *Vaapi::get_resolution_to_bitrate_map(metadata.fps)
.get(&metadata.get_res())
.unwrap();
} else {
return *Amf::get_resolution_to_bitrate_map(metadata.fps)
.get(&metadata.get_res())
Expand Down
26 changes: 26 additions & 0 deletions cli/src/cli_util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,32 @@ pub fn standard_cli_check(
}
}

pub fn validate_vaapi_options(
encoder: &String,
vaapi_device: &String,
ten_bit: bool,
was_ui_opened: bool,
) {
if !encoder.contains("vaapi") {
return;
}

if !cfg!(target_os = "linux") {
println!("Error: VAAPI encoders are currently supported only on Linux");
error_with_ack(was_ui_opened);
}

if !Path::new(vaapi_device).exists() {
println!("Error: VAAPI device [{}] does not exist", vaapi_device);
error_with_ack(was_ui_opened);
}

if encoder == "h264_vaapi" && ten_bit {
println!("Error: 10-bit encoding is not supported by h264_vaapi");
error_with_ack(was_ui_opened);
}
}

pub fn error_with_ack(ack: bool) {
// want to give the user a chance to acknowledge the error
if ack {
Expand Down
25 changes: 23 additions & 2 deletions cli/src/supported.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
const SUPPORTED_ENCODERS: [&'static str; 10] = [
const SUPPORTED_ENCODERS: [&'static str; 13] = [
"h264_nvenc",
"hevc_nvenc",
"h264_amf",
Expand All @@ -9,6 +9,9 @@ const SUPPORTED_ENCODERS: [&'static str; 10] = [
"h264_videotoolbox",
"hevc_videotoolbox",
"prores_videotoolbox",
"h264_vaapi",
"hevc_vaapi",
"av1_vaapi",
];

const ENCODE_FILES: [&'static str; 8] = [
Expand All @@ -26,10 +29,28 @@ pub fn is_encoder_supported(potential_encoder: &String) -> bool {
return SUPPORTED_ENCODERS.contains(&potential_encoder.as_str());
}

pub fn get_supported_encoders() -> [&'static str; 10] {
pub fn get_supported_encoders() -> [&'static str; 13] {
return SUPPORTED_ENCODERS;
}

pub fn get_supported_inputs() -> [&'static str; 8] {
return ENCODE_FILES;
}

#[cfg(test)]
mod tests {
use super::{get_supported_encoders, is_encoder_supported};

#[test]
fn av1_vaapi_is_supported() {
assert!(is_encoder_supported(&"av1_vaapi".to_string()));
}

#[test]
fn vaapi_encoders_are_listed_last() {
assert_eq!(
&get_supported_encoders()[10..],
&["h264_vaapi", "hevc_vaapi", "av1_vaapi"]
);
}
}
3 changes: 3 additions & 0 deletions codecs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ pub mod nvenc;
pub mod permute;
pub mod qsv;
mod resolutions;
pub mod vaapi;
pub mod vendor;

pub fn get_vendor_for_codec(codec: &String) -> Vendor {
Expand All @@ -19,6 +20,8 @@ pub fn get_vendor_for_codec(codec: &String) -> Vendor {
return Vendor::IntelQSV;
} else if codec.contains("videotoolbox") {
return Vendor::Apple;
} else if codec.contains("vaapi") {
return Vendor::Vaapi;
}

return Vendor::Unknown;
Expand Down
Loading
Loading