1
0
Fork 0
mirror of https://github.com/immich-app/immich.git synced 2024-12-28 06:31:58 +00:00

always use hw filters when hwa is enabled

This commit is contained in:
mertalev 2024-11-22 03:00:30 -05:00
parent efb4394c7b
commit d846f7fc7f
No known key found for this signature in database
GPG key ID: CA85EF6600C9E8AD

View file

@ -326,6 +326,32 @@ export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig {
this.devices = this.validateDevices(devices); this.devices = this.validateDevices(devices);
} }
getScalingFilter(videoStream: VideoStreamInfo, format: string) {
return `scale_${this.config.accel}=${this.getScaling(videoStream)}:format=${format}`;
}
getHwDecodeFilterOptions(videoStream: VideoStreamInfo) {
const options = [];
const tonemapOptions = this.getToneMapping(videoStream);
if (this.shouldScale(videoStream) || tonemapOptions.length === 0) {
const format = tonemapOptions.length === 0 ? 'nv12' : 'p010';
options.push(this.getScalingFilter(videoStream, format));
} else if (tonemapOptions.length > 0) {
options.push('format=p010');
}
options.push(...tonemapOptions);
if (options.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
options.push('format=nv12');
}
return options;
}
getFilterOptions(videoStream: VideoStreamInfo) {
return this.config.accelDecode
? this.getHwDecodeFilterOptions(videoStream)
: [`hwupload_${this.config.accel}`, ...this.getHwDecodeFilterOptions(videoStream)];
}
getSupportedCodecs() { getSupportedCodecs() {
return [VideoCodec.H264, VideoCodec.HEVC]; return [VideoCodec.H264, VideoCodec.HEVC];
} }
@ -369,6 +395,20 @@ export class BaseHWConfig extends BaseConfig implements VideoCodecHWConfig {
return `/dev/dri/${deviceName}`; return `/dev/dri/${deviceName}`;
} }
getInputThreadOptions() {
if (this.config.accelDecode) {
return [`-threads 1`];
}
return [];
}
getOutputThreadOptions() {
if (this.config.accelDecode) {
return [];
}
return super.getOutputThreadOptions();
}
} }
export class ThumbnailConfig extends BaseConfig { export class ThumbnailConfig extends BaseConfig {
@ -503,15 +543,11 @@ export class AV1Config extends BaseConfig {
} }
} }
export class NvencSwDecodeConfig extends BaseHWConfig { export class NvencConfig extends BaseHWConfig {
getSupportedCodecs() { getSupportedCodecs() {
return [VideoCodec.H264, VideoCodec.HEVC, VideoCodec.AV1]; return [VideoCodec.H264, VideoCodec.HEVC, VideoCodec.AV1];
} }
getBaseInputOptions() {
return ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'];
}
getBaseOutputOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) { getBaseOutputOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) {
const options = [ const options = [
// below settings recommended from https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/ffmpeg-with-nvidia-gpu/index.html#command-line-for-latency-tolerant-high-quality-transcoding // below settings recommended from https://docs.nvidia.com/video-technologies/video-codec-sdk/12.0/ffmpeg-with-nvidia-gpu/index.html#command-line-for-latency-tolerant-high-quality-transcoding
@ -530,16 +566,6 @@ export class NvencSwDecodeConfig extends BaseHWConfig {
return options; return options;
} }
getFilterOptions(videoStream: VideoStreamInfo) {
const options = this.getToneMapping(videoStream);
options.push('hwupload_cuda');
if (this.shouldScale(videoStream)) {
options.push(`scale_cuda=${this.getScaling(videoStream)}:format=nv12`);
}
return options;
}
getPresetOptions() { getPresetOptions() {
let presetIndex = this.getPresetIndex(); let presetIndex = this.getPresetIndex();
if (presetIndex < 0) { if (presetIndex < 0) {
@ -569,10 +595,6 @@ export class NvencSwDecodeConfig extends BaseHWConfig {
} }
} }
getThreadOptions() {
return [];
}
getRefs() { getRefs() {
const bframes = this.getBFrames(); const bframes = this.getBFrames();
if (bframes > 0 && bframes < 3 && this.config.refs < 3) { if (bframes > 0 && bframes < 3 && this.config.refs < 3) {
@ -580,27 +602,14 @@ export class NvencSwDecodeConfig extends BaseHWConfig {
} }
return this.config.refs; return this.config.refs;
} }
}
export class NvencHwDecodeConfig extends NvencSwDecodeConfig {
getBaseInputOptions() { getBaseInputOptions() {
if (!this.config.accelDecode) {
return ['-init_hw_device cuda=cuda:0', '-filter_hw_device cuda'];
}
return ['-hwaccel cuda', '-hwaccel_output_format cuda', '-noautorotate', ...this.getInputThreadOptions()]; return ['-hwaccel cuda', '-hwaccel_output_format cuda', '-noautorotate', ...this.getInputThreadOptions()];
} }
getFilterOptions(videoStream: VideoStreamInfo) {
const options = [];
if (this.shouldScale(videoStream)) {
options.push(`scale_cuda=${this.getScaling(videoStream)}`);
}
options.push(...this.getToneMapping(videoStream));
if (options.length > 0) {
options[options.length - 1] += ':format=nv12';
} else if (!videoStream.pixelFormat.endsWith('420p')) {
options.push('format=nv12');
}
return options;
}
getToneMapping(videoStream: VideoStreamInfo) { getToneMapping(videoStream: VideoStreamInfo) {
if (!this.shouldToneMap(videoStream)) { if (!this.shouldToneMap(videoStream)) {
return []; return [];
@ -616,28 +625,36 @@ export class NvencHwDecodeConfig extends NvencSwDecodeConfig {
'tonemap_mode=lum', 'tonemap_mode=lum',
`transfer=${transfer}`, `transfer=${transfer}`,
'peak=100', 'peak=100',
'format=nv12',
]; ];
return [`tonemap_cuda=${tonemapOptions.join(':')}`]; return [`tonemap_cuda=${tonemapOptions.join(':')}`];
} }
getInputThreadOptions() {
return [`-threads 1`];
}
getOutputThreadOptions() {
return [];
}
} }
export class QsvSwDecodeConfig extends BaseHWConfig { export class QsvConfig extends BaseHWConfig {
getBaseInputOptions() { getBaseInputOptions() {
if (this.devices.length === 0) { if (this.devices.length === 0) {
throw new Error('No QSV device found'); throw new Error('No QSV device found');
} }
let qsvString = '';
const hwDevice = this.getPreferredHardwareDevice(); const hwDevice = this.getPreferredHardwareDevice();
if (this.config.accelDecode) {
const options = [
'-hwaccel qsv',
'-hwaccel_output_format qsv',
'-async_depth 4',
'-noautorotate',
...this.getInputThreadOptions(),
];
if (hwDevice) {
options.push(`-qsv_device ${hwDevice}`);
}
return options;
}
let qsvString = '';
if (hwDevice) { if (hwDevice) {
qsvString = `,child_device=${hwDevice}`; qsvString = `,child_device=${hwDevice}`;
} }
@ -654,15 +671,6 @@ export class QsvSwDecodeConfig extends BaseHWConfig {
return options; return options;
} }
getFilterOptions(videoStream: VideoStreamInfo) {
const options = this.getToneMapping(videoStream);
options.push('hwupload=extra_hw_frames=64');
if (this.shouldScale(videoStream)) {
options.push(`scale_qsv=${this.getScaling(videoStream)}:mode=hq:format=nv12`);
}
return options;
}
getPresetOptions() { getPresetOptions() {
let presetIndex = this.getPresetIndex(); let presetIndex = this.getPresetIndex();
if (presetIndex < 0) { if (presetIndex < 0) {
@ -708,44 +716,9 @@ export class QsvSwDecodeConfig extends BaseHWConfig {
getScaling(videoStream: VideoStreamInfo): string { getScaling(videoStream: VideoStreamInfo): string {
return super.getScaling(videoStream, 1); return super.getScaling(videoStream, 1);
} }
}
export class QsvHwDecodeConfig extends QsvSwDecodeConfig { getScalingFilter(videoStream: VideoStreamInfo, format: string) {
getBaseInputOptions() { return `scale_qsv=${this.getScaling(videoStream)}:async_depth=4:mode=hq:format=${format}`;
if (this.devices.length === 0) {
throw new Error('No QSV device found');
}
const options = [
'-hwaccel qsv',
'-hwaccel_output_format qsv',
'-async_depth 4',
'-noautorotate',
...this.getInputThreadOptions(),
];
const hwDevice = this.getPreferredHardwareDevice();
if (hwDevice) {
options.push(`-qsv_device ${hwDevice}`);
}
return options;
}
getFilterOptions(videoStream: VideoStreamInfo) {
const options = [];
const tonemapOptions = this.getToneMapping(videoStream);
if (this.shouldScale(videoStream) || tonemapOptions.length === 0) {
let scaling = `scale_qsv=${this.getScaling(videoStream)}:async_depth=4:mode=hq`;
if (tonemapOptions.length === 0) {
scaling += ':format=nv12';
}
options.push(scaling);
}
options.push(...tonemapOptions);
if (options.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
options.push('format=nv12');
}
return options;
} }
getToneMapping(videoStream: VideoStreamInfo): string[] { getToneMapping(videoStream: VideoStreamInfo): string[] {
@ -772,19 +745,27 @@ export class QsvHwDecodeConfig extends QsvSwDecodeConfig {
'hwmap=derive_device=qsv:reverse=1,format=qsv', 'hwmap=derive_device=qsv:reverse=1,format=qsv',
]; ];
} }
getInputThreadOptions() {
return [`-threads 1`];
}
} }
export class VaapiSwDecodeConfig extends BaseHWConfig { export class VaapiConfig extends BaseHWConfig {
getBaseInputOptions() { getBaseInputOptions() {
if (this.devices.length === 0) { if (this.devices.length === 0) {
throw new Error('No VAAPI device found'); throw new Error('No VAAPI device found');
} }
let hwDevice = this.getPreferredHardwareDevice(); let hwDevice = this.getPreferredHardwareDevice();
if (this.config.accelDecode) {
const options = [
'-hwaccel vaapi',
'-hwaccel_output_format vaapi',
'-noautorotate',
...this.getInputThreadOptions(),
];
if (hwDevice) {
options.push(`-hwaccel_device ${hwDevice}`);
}
}
if (!hwDevice) { if (!hwDevice) {
hwDevice = `/dev/dri/${this.devices[0]}`; hwDevice = `/dev/dri/${this.devices[0]}`;
} }
@ -792,16 +773,6 @@ export class VaapiSwDecodeConfig extends BaseHWConfig {
return [`-init_hw_device vaapi=accel:${hwDevice}`, '-filter_hw_device accel']; return [`-init_hw_device vaapi=accel:${hwDevice}`, '-filter_hw_device accel'];
} }
getFilterOptions(videoStream: VideoStreamInfo) {
const options = this.getToneMapping(videoStream);
options.push('hwupload=extra_hw_frames=64');
if (this.shouldScale(videoStream)) {
options.push(`scale_vaapi=${this.getScaling(videoStream)}:mode=hq:out_range=pc:format=nv12`);
}
return options;
}
getPresetOptions() { getPresetOptions() {
let presetIndex = this.getPresetIndex(); let presetIndex = this.getPresetIndex();
if (presetIndex < 0) { if (presetIndex < 0) {
@ -843,43 +814,9 @@ export class VaapiSwDecodeConfig extends BaseHWConfig {
useCQP() { useCQP() {
return this.config.cqMode !== CQMode.ICQ || this.config.targetVideoCodec === VideoCodec.VP9; return this.config.cqMode !== CQMode.ICQ || this.config.targetVideoCodec === VideoCodec.VP9;
} }
}
export class VaapiHwDecodeConfig extends VaapiSwDecodeConfig { getScalingFilter(videoStream: VideoStreamInfo, format: string) {
getBaseInputOptions() { return `scale_vaapi=${this.getScaling(videoStream)}:mode=hq:out_range=pc:format=${format}`;
if (this.devices.length === 0) {
throw new Error('No VAAPI device found');
}
const options = [
'-hwaccel vaapi',
'-hwaccel_output_format vaapi',
'-noautorotate',
...this.getInputThreadOptions(),
];
const hwDevice = this.getPreferredHardwareDevice();
if (hwDevice) {
options.push(`-hwaccel_device ${hwDevice}`);
}
return options;
}
getFilterOptions(videoStream: VideoStreamInfo) {
const options = [];
const tonemapOptions = this.getToneMapping(videoStream);
if (this.shouldScale(videoStream) || tonemapOptions.length === 0) {
let scaling = `scale_vaapi=${this.getScaling(videoStream)}:mode=hq:out_range=pc`;
if (tonemapOptions.length === 0) {
scaling += ':format=nv12';
}
options.push(scaling);
}
options.push(...tonemapOptions);
if (options.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
options.push('format=nv12');
}
return options;
} }
getToneMapping(videoStream: VideoStreamInfo): string[] { getToneMapping(videoStream: VideoStreamInfo): string[] {
@ -906,29 +843,33 @@ export class VaapiHwDecodeConfig extends VaapiSwDecodeConfig {
'hwmap=derive_device=vaapi:reverse=1,format=vaapi', 'hwmap=derive_device=vaapi:reverse=1,format=vaapi',
]; ];
} }
getInputThreadOptions() {
return [`-threads 1`];
}
} }
export class RkmppSwDecodeConfig extends BaseHWConfig { export class RkmppConfig extends BaseHWConfig {
protected hasMaliOpenCL: boolean;
constructor( constructor(
protected config: SystemConfigFFmpegDto, protected config: SystemConfigFFmpegDto,
devices: string[] = [], devices: string[] = [],
hasMaliOpenCL = false,
) { ) {
super(config, devices); super(config, devices);
this.hasMaliOpenCL = hasMaliOpenCL;
} }
eligibleForTwoPass(): boolean { eligibleForTwoPass(): boolean {
return false; return false;
} }
getBaseInputOptions(): string[] { getBaseInputOptions() {
if (this.devices.length === 0) { if (this.devices.length === 0) {
throw new Error('No RKMPP device found'); throw new Error('No RKMPP device found');
} }
return [];
if (this.config.accelDecode) {
return ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga', '-noautorotate'];
}
return ['-init_hw_device rkmpp=hw', '-filter_hw_device hw'];
} }
getPresetOptions() { getPresetOptions() {
@ -961,30 +902,6 @@ export class RkmppSwDecodeConfig extends BaseHWConfig {
return [VideoCodec.H264, VideoCodec.HEVC]; return [VideoCodec.H264, VideoCodec.HEVC];
} }
getVideoCodec(): string {
return `${this.config.targetVideoCodec}_rkmpp`;
}
}
export class RkmppHwDecodeConfig extends RkmppSwDecodeConfig {
protected hasMaliOpenCL: boolean;
constructor(
protected config: SystemConfigFFmpegDto,
devices: string[] = [],
hasMaliOpenCL = false,
) {
super(config, devices);
this.hasMaliOpenCL = hasMaliOpenCL;
}
getBaseInputOptions() {
if (this.devices.length === 0) {
throw new Error('No RKMPP device found');
}
return ['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga', '-noautorotate'];
}
getFilterOptions(videoStream: VideoStreamInfo) { getFilterOptions(videoStream: VideoStreamInfo) {
if (this.shouldToneMap(videoStream)) { if (this.shouldToneMap(videoStream)) {
const { primaries, transfer, matrix } = this.getColors(); const { primaries, transfer, matrix } = this.getColors();