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 @@
+
+
+
+
+
+
+
+
+
+