mirror of
https://github.com/immich-app/immich
synced 2025-11-14 17:36:12 +00:00
feat(server): transcoding hardware acceleration (#3171)
* added transcode configs for nvenc,qsv and vaapi * updated dev docker compose * added software fallback * working vaapi * minor fixes and added tests * updated api * compile libvips * move hwaccel settings to `hwaccel.yml` * changed default dockerfile, moved `readdir` call * removed unused import * minor cleanup * fix for arm build * added documentation, minor fixes * added intel driver * updated docs styling * uppercase codec and api names * formatting * added tests * updated docs * removed semicolons * added link to `hwaccel.yml` * added newlines * added `hwaccel` section to docker-compose.prod.yml * ensure mesa drivers are installed * switch to mimalloc for sharp * moved build version and sha256 to json * let libmfx set the render device * possible fix for vp9 on qsv * updated tests * formatting * review suggestions * semicolon * moved `LD_PRELOAD` to start script * switched to jellyfin's ffmpeg package * fixed dockerfile * use cqp instead of icq for qsv vp9 * updated dockerfile * added sha256sum for other platforms * fixtures
This commit is contained in:
parent
b9cda59172
commit
ee49f470b7
44 changed files with 1308 additions and 68 deletions
|
|
@ -14,37 +14,37 @@ class AssetStatsResponseDto {
|
|||
/// Returns a new [AssetStatsResponseDto] instance.
|
||||
AssetStatsResponseDto({
|
||||
required this.images,
|
||||
required this.total,
|
||||
required this.videos,
|
||||
required this.total,
|
||||
});
|
||||
|
||||
int images;
|
||||
|
||||
int total;
|
||||
|
||||
int videos;
|
||||
|
||||
int total;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is AssetStatsResponseDto &&
|
||||
other.images == images &&
|
||||
other.total == total &&
|
||||
other.videos == videos;
|
||||
other.videos == videos &&
|
||||
other.total == total;
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(images.hashCode) +
|
||||
(total.hashCode) +
|
||||
(videos.hashCode);
|
||||
(videos.hashCode) +
|
||||
(total.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'AssetStatsResponseDto[images=$images, total=$total, videos=$videos]';
|
||||
String toString() => 'AssetStatsResponseDto[images=$images, videos=$videos, total=$total]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'images'] = this.images;
|
||||
json[r'total'] = this.total;
|
||||
json[r'videos'] = this.videos;
|
||||
json[r'total'] = this.total;
|
||||
return json;
|
||||
}
|
||||
|
||||
|
|
@ -57,8 +57,8 @@ class AssetStatsResponseDto {
|
|||
|
||||
return AssetStatsResponseDto(
|
||||
images: mapValueOfType<int>(json, r'images')!,
|
||||
total: mapValueOfType<int>(json, r'total')!,
|
||||
videos: mapValueOfType<int>(json, r'videos')!,
|
||||
total: mapValueOfType<int>(json, r'total')!,
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
|
@ -107,8 +107,8 @@ class AssetStatsResponseDto {
|
|||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'images',
|
||||
'total',
|
||||
'videos',
|
||||
'total',
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ part of openapi.api;
|
|||
class SystemConfigFFmpegDto {
|
||||
/// Returns a new [SystemConfigFFmpegDto] instance.
|
||||
SystemConfigFFmpegDto({
|
||||
required this.accel,
|
||||
required this.crf,
|
||||
required this.maxBitrate,
|
||||
required this.preset,
|
||||
|
|
@ -24,6 +25,8 @@ class SystemConfigFFmpegDto {
|
|||
required this.twoPass,
|
||||
});
|
||||
|
||||
TranscodeHWAccel accel;
|
||||
|
||||
int crf;
|
||||
|
||||
String maxBitrate;
|
||||
|
|
@ -44,6 +47,7 @@ class SystemConfigFFmpegDto {
|
|||
|
||||
@override
|
||||
bool operator ==(Object other) => identical(this, other) || other is SystemConfigFFmpegDto &&
|
||||
other.accel == accel &&
|
||||
other.crf == crf &&
|
||||
other.maxBitrate == maxBitrate &&
|
||||
other.preset == preset &&
|
||||
|
|
@ -57,6 +61,7 @@ class SystemConfigFFmpegDto {
|
|||
@override
|
||||
int get hashCode =>
|
||||
// ignore: unnecessary_parenthesis
|
||||
(accel.hashCode) +
|
||||
(crf.hashCode) +
|
||||
(maxBitrate.hashCode) +
|
||||
(preset.hashCode) +
|
||||
|
|
@ -68,10 +73,11 @@ class SystemConfigFFmpegDto {
|
|||
(twoPass.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SystemConfigFFmpegDto[crf=$crf, maxBitrate=$maxBitrate, preset=$preset, targetAudioCodec=$targetAudioCodec, targetResolution=$targetResolution, targetVideoCodec=$targetVideoCodec, threads=$threads, transcode=$transcode, twoPass=$twoPass]';
|
||||
String toString() => 'SystemConfigFFmpegDto[accel=$accel, crf=$crf, maxBitrate=$maxBitrate, preset=$preset, targetAudioCodec=$targetAudioCodec, targetResolution=$targetResolution, targetVideoCodec=$targetVideoCodec, threads=$threads, transcode=$transcode, twoPass=$twoPass]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
json[r'accel'] = this.accel;
|
||||
json[r'crf'] = this.crf;
|
||||
json[r'maxBitrate'] = this.maxBitrate;
|
||||
json[r'preset'] = this.preset;
|
||||
|
|
@ -92,6 +98,7 @@ class SystemConfigFFmpegDto {
|
|||
final json = value.cast<String, dynamic>();
|
||||
|
||||
return SystemConfigFFmpegDto(
|
||||
accel: TranscodeHWAccel.fromJson(json[r'accel'])!,
|
||||
crf: mapValueOfType<int>(json, r'crf')!,
|
||||
maxBitrate: mapValueOfType<String>(json, r'maxBitrate')!,
|
||||
preset: mapValueOfType<String>(json, r'preset')!,
|
||||
|
|
@ -148,6 +155,7 @@ class SystemConfigFFmpegDto {
|
|||
|
||||
/// The list of required keys that must be present in a JSON.
|
||||
static const requiredKeys = <String>{
|
||||
'accel',
|
||||
'crf',
|
||||
'maxBitrate',
|
||||
'preset',
|
||||
|
|
|
|||
91
mobile/openapi/lib/model/transcode_hw_accel.dart
generated
Normal file
91
mobile/openapi/lib/model/transcode_hw_accel.dart
generated
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// AUTO-GENERATED FILE, DO NOT MODIFY!
|
||||
//
|
||||
// @dart=2.12
|
||||
|
||||
// ignore_for_file: unused_element, unused_import
|
||||
// ignore_for_file: always_put_required_named_parameters_first
|
||||
// ignore_for_file: constant_identifier_names
|
||||
// ignore_for_file: lines_longer_than_80_chars
|
||||
|
||||
part of openapi.api;
|
||||
|
||||
|
||||
class TranscodeHWAccel {
|
||||
/// Instantiate a new enum with the provided [value].
|
||||
const TranscodeHWAccel._(this.value);
|
||||
|
||||
/// The underlying value of this enum member.
|
||||
final String value;
|
||||
|
||||
@override
|
||||
String toString() => value;
|
||||
|
||||
String toJson() => value;
|
||||
|
||||
static const nvenc = TranscodeHWAccel._(r'nvenc');
|
||||
static const qsv = TranscodeHWAccel._(r'qsv');
|
||||
static const vaapi = TranscodeHWAccel._(r'vaapi');
|
||||
static const disabled = TranscodeHWAccel._(r'disabled');
|
||||
|
||||
/// List of all possible values in this [enum][TranscodeHWAccel].
|
||||
static const values = <TranscodeHWAccel>[
|
||||
nvenc,
|
||||
qsv,
|
||||
vaapi,
|
||||
disabled,
|
||||
];
|
||||
|
||||
static TranscodeHWAccel? fromJson(dynamic value) => TranscodeHWAccelTypeTransformer().decode(value);
|
||||
|
||||
static List<TranscodeHWAccel>? listFromJson(dynamic json, {bool growable = false,}) {
|
||||
final result = <TranscodeHWAccel>[];
|
||||
if (json is List && json.isNotEmpty) {
|
||||
for (final row in json) {
|
||||
final value = TranscodeHWAccel.fromJson(row);
|
||||
if (value != null) {
|
||||
result.add(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.toList(growable: growable);
|
||||
}
|
||||
}
|
||||
|
||||
/// Transformation class that can [encode] an instance of [TranscodeHWAccel] to String,
|
||||
/// and [decode] dynamic data back to [TranscodeHWAccel].
|
||||
class TranscodeHWAccelTypeTransformer {
|
||||
factory TranscodeHWAccelTypeTransformer() => _instance ??= const TranscodeHWAccelTypeTransformer._();
|
||||
|
||||
const TranscodeHWAccelTypeTransformer._();
|
||||
|
||||
String encode(TranscodeHWAccel data) => data.value;
|
||||
|
||||
/// Decodes a [dynamic value][data] to a TranscodeHWAccel.
|
||||
///
|
||||
/// If [allowNull] is true and the [dynamic value][data] cannot be decoded successfully,
|
||||
/// then null is returned. However, if [allowNull] is false and the [dynamic value][data]
|
||||
/// cannot be decoded successfully, then an [UnimplementedError] is thrown.
|
||||
///
|
||||
/// The [allowNull] is very handy when an API changes and a new enum value is added or removed,
|
||||
/// and users are still using an old app with the old code.
|
||||
TranscodeHWAccel? decode(dynamic data, {bool allowNull = true}) {
|
||||
if (data != null) {
|
||||
switch (data) {
|
||||
case r'nvenc': return TranscodeHWAccel.nvenc;
|
||||
case r'qsv': return TranscodeHWAccel.qsv;
|
||||
case r'vaapi': return TranscodeHWAccel.vaapi;
|
||||
case r'disabled': return TranscodeHWAccel.disabled;
|
||||
default:
|
||||
if (!allowNull) {
|
||||
throw ArgumentError('Unknown enum value to decode: $data');
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/// Singleton [TranscodeHWAccelTypeTransformer] instance.
|
||||
static TranscodeHWAccelTypeTransformer? _instance;
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue