diff --git a/package-lock.json b/package-lock.json index 7b9f13a1..22539e60 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18721,9 +18721,9 @@ } }, "typeconfig": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/typeconfig/-/typeconfig-2.0.7.tgz", - "integrity": "sha512-aShKfhwvPQFnMwBBFWsJhl1QQmDsdkx/vs7aKgxbGnLMW7W2djucEPGlUsmK3isMrTJAErmsr5CElacO/YFA6A==", + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/typeconfig/-/typeconfig-2.0.8.tgz", + "integrity": "sha512-D2Qfq1Ub6aZ/P24VGiyufuepClsHt9doe7xPf2YbmEOUtJRGgyQSDNamQp6wFuTfFKjpQIqi+6moQelkPI9BwQ==", "requires": { "optimist": "0.6.1" } diff --git a/package.json b/package.json index dd5d0b9b..35a319ad 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,7 @@ "sqlite3": "4.1.1", "ts-exif-parser": "0.1.4", "ts-node-iptc": "1.0.11", - "typeconfig": "2.0.7", + "typeconfig": "2.0.8", "typeorm": "0.2.21", "winston": "2.4.4" }, diff --git a/src/backend/model/fileprocessing/VideoProcessing.ts b/src/backend/model/fileprocessing/VideoProcessing.ts index 2dbe5c6a..050915f7 100644 --- a/src/backend/model/fileprocessing/VideoProcessing.ts +++ b/src/backend/model/fileprocessing/VideoProcessing.ts @@ -71,7 +71,10 @@ export class VideoProcessing { output: { path: outPath, codec: Config.Server.Media.Video.transcoding.codec, - format: Config.Server.Media.Video.transcoding.format + format: Config.Server.Media.Video.transcoding.format, + crf: Config.Server.Media.Video.transcoding.crf, + preset: Config.Server.Media.Video.transcoding.preset, + customOptions: Config.Server.Media.Video.transcoding.customOptions, } }; diff --git a/src/backend/model/threading/VideoConverterWorker.ts b/src/backend/model/threading/VideoConverterWorker.ts index bb5315df..e54a0226 100644 --- a/src/backend/model/threading/VideoConverterWorker.ts +++ b/src/backend/model/threading/VideoConverterWorker.ts @@ -3,6 +3,7 @@ import {promises as fsp} from 'fs'; import {FfmpegCommand} from 'fluent-ffmpeg'; import {FFmpegFactory} from '../FFmpegFactory'; import {ServerConfig} from '../../../common/config/private/PrivateConfig'; +import FFmpegPresets = ServerConfig.FFmpegPresets; export interface VideoConverterInput { @@ -12,6 +13,9 @@ export interface VideoConverterInput { bitRate?: number, resolution?: ServerConfig.resolutionType, fps?: number, + crf?: number, + preset?: ServerConfig.FFmpegPresets, + customOptions?: string[], codec: ServerConfig.codecType, format: ServerConfig.formatType }; @@ -67,6 +71,21 @@ export class VideoConverterWorker { if (input.output.fps) { command.fps(input.output.fps); } + + // set Constant Rate Factor (CRF) + if (input.output.crf) { + command.addOption(['-crf ' + input.output.crf]); + } + + // set preset + if (input.output.preset) { + command.addOption(['-preset ' + FFmpegPresets[input.output.preset]]); + } + // set any additional commands + if (input.output.customOptions) { + command.addOption(input.output.customOptions); + } + // set output format to force command.format(input.output.format) // save to file diff --git a/src/common/config/private/PrivateConfig.ts b/src/common/config/private/PrivateConfig.ts index 7654b749..50425345 100644 --- a/src/common/config/private/PrivateConfig.ts +++ b/src/common/config/private/PrivateConfig.ts @@ -29,6 +29,11 @@ export module ServerConfig { low = 1, medium = 2, high = 3 } + export enum FFmpegPresets { + ultrafast = 1, superfast = 2, veryfast = 3, faster = 4, fast = 5, medium = 6, + slow = 7, slower = 8, veryslow = 9, placebo = 10 + } + export type codecType = 'libvpx-vp9' | 'libx264' | 'libvpx' | 'libx265'; export type resolutionType = 240 | 360 | 480 | 720 | 1080 | 1440 | 2160 | 4320; @@ -252,6 +257,20 @@ export module ServerConfig { codec: codecType = 'libx264'; @ConfigProperty() format: formatType = 'mp4'; + @ConfigProperty({ + type: 'unsignedInt', + description: 'Constant Rate Factor. The range of the CRF scale is 0–51, where 0 is lossless, 23 is the default, and 51 is worst quality possible.', + max: 51 + }) + crf: number = 23; + @ConfigProperty({ + type: FFmpegPresets, + description: 'A preset is a collection of options that will provide a certain encoding speed to compression ratio' + }) + preset: FFmpegPresets = FFmpegPresets.medium; + + @ConfigProperty({arrayType: 'string', description: 'It will be sent to ffmpeg as it is, as custom options.'}) + customOptions: string[] = []; } @SubConfigClass() diff --git a/src/frontend/app/ui/settings/_abstract/settings-entry/settings-entry.component.ts b/src/frontend/app/ui/settings/_abstract/settings-entry/settings-entry.component.ts index dd26308b..3bcdad3a 100644 --- a/src/frontend/app/ui/settings/_abstract/settings-entry/settings-entry.component.ts +++ b/src/frontend/app/ui/settings/_abstract/settings-entry/settings-entry.component.ts @@ -31,6 +31,7 @@ export class SettingsEntryComponent implements ControlValueAccessor, Validator, @Input() placeholder: string; @Input() options: { key: number | string, value: number | string }[]; @Input() simplifiedMode = false; + @Input() allowSpaces = false; @Input() description: boolean; state: { isEnumType: boolean, @@ -99,7 +100,9 @@ export class SettingsEntryComponent implements ControlValueAccessor, Validator, if (this.state.type === 'array' && (this.state.arrayType === 'string' || this.isNumberArray)) { value = value.replace(new RegExp(',', 'g'), ';'); - value = value.replace(new RegExp(' ', 'g'), ';'); + if(this.allowSpaces === false) { + value = value.replace(new RegExp(' ', 'g'), ';'); + } this.state.value = value.split(';').filter((v: string) => v !== ''); if (this.isNumberArray) { this.state.value = this.state.value.map((v: string) => parseFloat(v)).filter((v: number) => !isNaN(v)); diff --git a/src/frontend/app/ui/settings/video/video.settings.component.html b/src/frontend/app/ui/settings/video/video.settings.component.html index 1953fb5f..cd15717b 100644 --- a/src/frontend/app/ui/settings/video/video.settings.component.html +++ b/src/frontend/app/ui/settings/video/video.settings.component.html @@ -108,6 +108,36 @@ + + + + + + + + + +