diff --git a/i18n/en.json b/i18n/en.json index 35396ef68f..dbbdb67786 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -427,7 +427,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 1f6691c87b..f45e6b0a82 100644 --- a/server/src/dtos/system-config.dto.ts +++ b/server/src/dtos/system-config.dto.ts @@ -16,6 +16,7 @@ import { ToneMappingSchema, TranscodeHardwareAccelerationSchema, TranscodePolicySchema, + VideoCodec, VideoCodecSchema, VideoContainerSchema, } from 'src/enum'; @@ -109,6 +110,9 @@ const SystemConfigFFmpegSchema = z }) .meta({ id: 'SystemConfigFFmpegRealtimeDto' }), }) + .refine((ffmpeg) => (ffmpeg.targetVideoCodec === VideoCodec.Av1 ? ffmpeg.threads <= 6 : true), { + error: 'AV1 threads/parallelism must be 0 or 1–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 7b14832155..39915992df 100644 --- a/server/src/services/system-config.service.spec.ts +++ b/server/src/services/system-config.service.spec.ts @@ -456,6 +456,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] AV1 threads/parallelism must be 0 or 1–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 33d6ba84f6..24f83c07f9 100644 --- a/web/src/routes/admin/system-settings/FFmpegSettings.svelte +++ b/web/src/routes/admin/system-settings/FFmpegSettings.svelte @@ -238,7 +238,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} />