Add native GPU-accelerated AV1 transcode capability
Post-grab async background swap, upgrade_locked flag to prevent the upgrade loop from re-inflating a locally-transcoded file, and a transcode-library CLI backfill for the existing catalog. Bitrate model calibrated against Silicon Valley's real HEVC bitrate, scaled by resolution and AV1's encoding efficiency. HDR/2160p and anime excluded from this first pass. Jellyfin session polling throttles batch encoding back to 1 stream during active playback.
This commit is contained in:
parent
691fb39cbb
commit
d533301880
10 changed files with 924 additions and 15 deletions
|
|
@ -23,6 +23,8 @@ pub struct Config {
|
|||
pub sources: SourcesConfig,
|
||||
#[serde(default)]
|
||||
pub notifications: NotificationsConfig,
|
||||
#[serde(default)]
|
||||
pub transcode: TranscodeConfig,
|
||||
}
|
||||
|
||||
/// Where the TUI's "add show" flow places new series by default. Sonarr/
|
||||
|
|
@ -277,6 +279,114 @@ pub struct JellyfinConfig {
|
|||
pub api_key: String,
|
||||
}
|
||||
|
||||
/// GPU-accelerated AV1 transcode: re-encodes freshly-grabbed and existing
|
||||
/// library files down to a space-reasonable size instead of keeping
|
||||
/// whatever the source release happened to be (REMUX, huge season packs,
|
||||
/// etc). `enabled` defaults false — this needs a manual calibration pass
|
||||
/// against real content on the target GPU before it's safe to run
|
||||
/// unattended against a whole library.
|
||||
#[derive(Debug, Clone, Deserialize)]
|
||||
pub struct TranscodeConfig {
|
||||
#[serde(default)]
|
||||
pub enabled: bool,
|
||||
/// Tight on purpose — the actual pace is bottlenecked by encode time
|
||||
/// (minutes per file), not this interval; a short poll just means a
|
||||
/// freshly-completed job's slot gets refilled promptly instead of
|
||||
/// sitting idle for the rest of a longer interval.
|
||||
#[serde(default = "default_transcode_poll_interval_secs")]
|
||||
pub poll_interval_secs: u64,
|
||||
#[serde(default = "default_vaapi_device")]
|
||||
pub vaapi_device: String,
|
||||
#[serde(default = "default_parallelism_min")]
|
||||
pub parallelism_min: usize,
|
||||
/// Ramp-up ceiling for concurrent encode streams during a backfill —
|
||||
/// tune this against how many simultaneous `av1_vaapi` sessions the
|
||||
/// target GPU can actually sustain before per-stream throughput starts
|
||||
/// dropping, not just picked arbitrarily.
|
||||
#[serde(default = "default_parallelism_max")]
|
||||
pub parallelism_max: usize,
|
||||
/// The "looks fine, no complaints" calibration reference: a real
|
||||
/// bitrate (Mbps, in kbps here) from content already in the library at
|
||||
/// `reference_height` that the user is happy with. New AV1 encodes are
|
||||
/// targeted relative to this, scaled by resolution and AV1's encoding
|
||||
/// efficiency, rather than picking a bitrate out of thin air.
|
||||
#[serde(default = "default_reference_bitrate_kbps")]
|
||||
pub reference_bitrate_kbps: u32,
|
||||
#[serde(default = "default_reference_height")]
|
||||
pub reference_height: u32,
|
||||
/// AV1 reaches equivalent perceived quality to HEVC at a meaningfully
|
||||
/// lower bitrate — this factor is applied on top of the resolution
|
||||
/// scaling so the AV1 target isn't just a like-for-like copy of the
|
||||
/// HEVC/H264 reference bitrate. Conservative (not maximally aggressive)
|
||||
/// on purpose: erring toward "still clearly smaller" over "as small as
|
||||
/// AV1 could theoretically go" leaves margin against visible artifacts.
|
||||
#[serde(default = "default_av1_efficiency_factor")]
|
||||
pub av1_efficiency_factor: f32,
|
||||
/// HDR10/Dolby Vision metadata preservation through the GPU encoder
|
||||
/// hasn't been verified yet — excluded from both the backfill and the
|
||||
/// post-grab path until that's specifically checked on a few samples.
|
||||
#[serde(default = "default_exclude_hdr")]
|
||||
pub exclude_hdr: bool,
|
||||
/// Excludes the 2160p tier from the first pass for the same reason as
|
||||
/// `exclude_hdr` (most current 4K content in this library is HDR
|
||||
/// anyway) — revisit once HDR handling is confirmed safe.
|
||||
#[serde(default = "default_exclude_min_height")]
|
||||
pub exclude_min_height: u32,
|
||||
}
|
||||
|
||||
impl Default for TranscodeConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: false,
|
||||
poll_interval_secs: default_transcode_poll_interval_secs(),
|
||||
vaapi_device: default_vaapi_device(),
|
||||
parallelism_min: default_parallelism_min(),
|
||||
parallelism_max: default_parallelism_max(),
|
||||
reference_bitrate_kbps: default_reference_bitrate_kbps(),
|
||||
reference_height: default_reference_height(),
|
||||
av1_efficiency_factor: default_av1_efficiency_factor(),
|
||||
exclude_hdr: default_exclude_hdr(),
|
||||
exclude_min_height: default_exclude_min_height(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn default_transcode_poll_interval_secs() -> u64 {
|
||||
60
|
||||
}
|
||||
|
||||
fn default_vaapi_device() -> String {
|
||||
"/dev/dri/renderD128".to_string()
|
||||
}
|
||||
|
||||
fn default_parallelism_min() -> usize {
|
||||
1
|
||||
}
|
||||
|
||||
fn default_parallelism_max() -> usize {
|
||||
4
|
||||
}
|
||||
|
||||
fn default_reference_bitrate_kbps() -> u32 {
|
||||
5320
|
||||
}
|
||||
|
||||
fn default_reference_height() -> u32 {
|
||||
1080
|
||||
}
|
||||
|
||||
fn default_av1_efficiency_factor() -> f32 {
|
||||
0.7
|
||||
}
|
||||
|
||||
fn default_exclude_hdr() -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
fn default_exclude_min_height() -> u32 {
|
||||
2000
|
||||
}
|
||||
|
||||
/// TVDB v4 API key, exchanged for a short-lived JWT at request time.
|
||||
#[derive(Debug, Clone, Default, Deserialize)]
|
||||
pub struct TvdbConfig {
|
||||
|
|
|
|||
|
|
@ -143,6 +143,7 @@ pub struct HealthDetail {
|
|||
pub last_import_cycle: Option<CycleInfo>,
|
||||
pub last_search_cycle: Option<CycleInfo>,
|
||||
pub last_upgrade_cycle: Option<CycleInfo>,
|
||||
pub last_transcode_cycle: Option<CycleInfo>,
|
||||
pub search_halted: bool,
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue