Add AV1 transcoding support (#8491)

* Add AV1 transcoding support

- AV1 encoding on CPU via SVT-AV1 (libsvtav1 in ffmpeg)
- Supports CRF and optionally capped CRF (max bitrate)
- Tested playback successfully in Chrome Win+Android, Firefox Win+Linux, Android app

* AV1: Add support for encoding threads option

* Revert previous commit; specifying params multiple times is bad

We need to specify all svtav1-params at once, so putting the thread option into getThreadOptions is not possible.

* AV1: Override VAAPI getSupportedCodecs as it does not yet support AV1 unlike nvenc, qsv, amf

* Change BaseHWConfig supported codecs to only H264/HEVC

Configs that support VP9 and/or AV1 need to override getSupportedCodecs()

* Set SVT-AV1 threads with svtav1-params, remove duplicate block in NVENCConfig

* AV1Config: Fix empty svtav1-params array being added to options

* add tests

* update api

* allow crf-based two-pass mode

* formatting

* suggest 35

---------

Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
This commit is contained in:
N00MKRAD 2024-04-11 07:26:27 +02:00 committed by GitHub
parent ad5d115abe
commit f1ca1794a1
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 215 additions and 6 deletions

Binary file not shown.

View file

@ -124,7 +124,7 @@ class BaseConfig implements VideoCodecSWConfig {
return false;
}
return this.isBitrateConstrained() || this.config.targetVideoCodec === VideoCodec.VP9;
return this.isBitrateConstrained();
}
getBitrateDistribution() {
@ -265,7 +265,7 @@ export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig {
}
getSupportedCodecs() {
return [VideoCodec.H264, VideoCodec.HEVC, VideoCodec.VP9];
return [VideoCodec.H264, VideoCodec.HEVC];
}
validateDevices(devices: string[]) {
@ -394,6 +394,44 @@ export class VP9Config extends BaseConfig {
getThreadOptions() {
return ['-row-mt 1', ...super.getThreadOptions()];
}
eligibleForTwoPass() {
return this.config.twoPass;
}
}
export class AV1Config extends BaseConfig {
getPresetOptions() {
const speed = this.getPresetIndex() + 4; // Use 4 as slowest, giving us an effective range of 4-12 which is far more useful than 0-8
if (speed >= 0) {
return [`-preset ${speed}`];
}
return [];
}
getBitrateOptions() {
const options = [`-crf ${this.config.crf}`];
const bitrates = this.getBitrateDistribution();
const svtparams = [];
if (this.config.threads > 0) {
svtparams.push(`lp=${this.config.threads}`);
}
if (bitrates.max > 0) {
svtparams.push(`mbr=${bitrates.max}${bitrates.unit}`);
}
if (svtparams.length > 0) {
options.push(`-svtav1-params ${svtparams.join(':')}`);
}
return options;
}
getThreadOptions() {
return []; // Already set above with svtav1-params
}
eligibleForTwoPass() {
return this.config.twoPass;
}
}
export class NVENCConfig extends BaseHWConfig {
@ -527,6 +565,10 @@ export class QSVConfig extends BaseHWConfig {
return options;
}
getSupportedCodecs() {
return [VideoCodec.H264, VideoCodec.HEVC, VideoCodec.VP9];
}
// recommended from https://github.com/intel/media-delivery/blob/master/doc/benchmarks/intel-iris-xe-max-graphics/intel-iris-xe-max-graphics.md
getBFrames() {
if (this.config.bframes < 0) {
@ -605,6 +647,10 @@ export class VAAPIConfig extends BaseHWConfig {
return options;
}
getSupportedCodecs() {
return [VideoCodec.H264, VideoCodec.HEVC, VideoCodec.VP9];
}
useCQP() {
return this.config.cqMode !== CQMode.ICQ || this.config.targetVideoCodec === VideoCodec.VP9;
}