diff --git a/i18n/en.json b/i18n/en.json index 0acfe68fa3..cdb79e5ebd 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -446,7 +446,7 @@ "transcoding_temporal_aq": "Temporal AQ", "transcoding_temporal_aq_description": "Applies only to NVENC. Temporal Adaptive Quantization increases quality of high-detail, low-motion scenes. May not be compatible with older devices.", "transcoding_threads": "Threads", - "transcoding_threads_description": "Higher values lead to faster encoding, but leave less room for the server to process other tasks while active. This value should not be more than the number of CPU cores. Maximizes utilization if set to 0.", + "transcoding_threads_description": "Higher values lead to faster encoding, but leave less room for the server to process other tasks while active. This value should not be more than the number of CPU cores. Maximizes utilization if set to 0.{av1, select, true { The AV1 encoder uses a number between 1–6 describing the amount of parallelism, instead of limiting to a specific number of threads.} other {}}", "transcoding_tone_mapping": "Tone-mapping", "transcoding_tone_mapping_description": "Attempts to preserve the appearance of HDR videos when converted to SDR. Each algorithm makes different tradeoffs for color, detail and brightness. Hable preserves detail, Mobius preserves color, and Reinhard preserves brightness.", "transcoding_transcode_policy": "Transcode policy", diff --git a/server/src/dtos/system-config.dto.ts b/server/src/dtos/system-config.dto.ts index a50b7abe87..e0387ac36c 100644 --- a/server/src/dtos/system-config.dto.ts +++ b/server/src/dtos/system-config.dto.ts @@ -18,6 +18,7 @@ import { ToneMappingSchema, TranscodeHardwareAccelerationSchema, TranscodePolicySchema, + VideoCodec, VideoCodecSchema, VideoContainerSchema, } from 'src/enum'; @@ -126,6 +127,9 @@ const SystemConfigFFmpegSchema = z }) .meta({ id: 'SystemConfigFFmpegRealtimeDto' }), }) + .refine((ffmpeg) => (ffmpeg.targetVideoCodec === VideoCodec.Av1 ? ffmpeg.threads <= 6 : true), { + error: 'Threads: for AV1, parallelism must be 0–6', + }) .meta({ id: 'SystemConfigFFmpegDto' }); const SystemConfigJobSchema = z diff --git a/server/src/services/system-config.service.spec.ts b/server/src/services/system-config.service.spec.ts index 08851da96a..52173e2794 100644 --- a/server/src/services/system-config.service.spec.ts +++ b/server/src/services/system-config.service.spec.ts @@ -459,6 +459,11 @@ describe(SystemConfigService.name, () => { }, { should: 'warn for top level unknown options', warn: true, config: { unknownOption: true } }, { should: 'warn for nested unknown options', warn: true, config: { ffmpeg: { unknownOption: true } } }, + { + should: 'validate av1 parallelism setting', + config: { ffmpeg: { targetVideoCodec: VideoCodec.Av1, threads: 7 } }, + throws: '[ffmpeg] Threads: for AV1, parallelism must be 0–6', + }, ]; for (const test of tests) { diff --git a/web/src/routes/admin/system-settings/FFmpegSettings.svelte b/web/src/routes/admin/system-settings/FFmpegSettings.svelte index f0436e0bf7..d7d9315d76 100644 --- a/web/src/routes/admin/system-settings/FFmpegSettings.svelte +++ b/web/src/routes/admin/system-settings/FFmpegSettings.svelte @@ -241,7 +241,9 @@ inputType={SettingInputFieldType.NUMBER} {disabled} label={$t('admin.transcoding_threads')} - description={$t('admin.transcoding_threads_description')} + description={$t('admin.transcoding_threads_description', { + values: { av1: configToEdit.ffmpeg.targetVideoCodec === VideoCodec.Av1 }, + })} bind:value={configToEdit.ffmpeg.threads} isEdited={configToEdit.ffmpeg.threads !== config.ffmpeg.threads} />