diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index 637e5fa248..6c568f3625 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -2053,14 +2053,19 @@ describe(MediaService.name, () => { twoPass: false, }, ); + }); - storageMock.readdir.mockResolvedValue(['renderD129', 'renderD128']); + it('should prefer higher index gpu node', async () => { + storageMock.readdir.mockResolvedValue(['renderD129', 'renderD130', 'renderD128']); + mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer); + configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_ACCEL, value: TranscodeHWAccel.VAAPI }]); + assetMock.getByIds.mockResolvedValue([assetStub.video]); await sut.handleVideoConversion({ id: assetStub.video.id }); expect(mediaMock.transcode).toHaveBeenCalledWith( '/original/path.ext', 'upload/encoded-video/user-id/as/se/asset-id.mp4', { - inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD129', '-filter_hw_device accel'], + inputOptions: ['-init_hw_device vaapi=accel:/dev/dri/renderD130', '-filter_hw_device accel'], outputOptions: [ `-c:v h264_vaapi`, '-c:a copy', diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index 00623cecbe..8a4ca4ce3e 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -50,7 +50,8 @@ import { usePagination } from 'src/utils/pagination'; export class MediaService { private configCore: SystemConfigCore; private storageCore: StorageCore; - private hasOpenCL?: boolean = undefined; + private openCL: boolean | null = null; + private devices: string[] | null = null; constructor( @Inject(IAssetRepository) private assetRepository: IAssetRepository, @@ -492,36 +493,21 @@ export class MediaService { private async getHWCodecConfig(config: SystemConfigFFmpegDto) { let handler: VideoCodecHWConfig; - let devices: string[]; switch (config.accel) { case TranscodeHWAccel.NVENC: { handler = new NVENCConfig(config); break; } case TranscodeHWAccel.QSV: { - devices = await this.storageRepository.readdir('/dev/dri'); - handler = new QSVConfig(config, devices); + handler = new QSVConfig(config, await this.getDevices()); break; } case TranscodeHWAccel.VAAPI: { - devices = await this.storageRepository.readdir('/dev/dri'); - handler = new VAAPIConfig(config, devices); + handler = new VAAPIConfig(config, await this.getDevices()); break; } case TranscodeHWAccel.RKMPP: { - if (this.hasOpenCL === undefined) { - try { - const maliIcdStat = await this.storageRepository.stat('/etc/OpenCL/vendors/mali.icd'); - const maliDeviceStat = await this.storageRepository.stat('/dev/mali0'); - this.hasOpenCL = maliIcdStat.isFile() && maliDeviceStat.isCharacterDevice(); - } catch { - this.logger.warn('OpenCL not available for transcoding, using CPU instead.'); - this.hasOpenCL = false; - } - } - - devices = await this.storageRepository.readdir('/dev/dri'); - handler = new RKMPPConfig(config, devices, this.hasOpenCL); + handler = new RKMPPConfig(config, await this.getDevices(), await this.hasOpenCL()); break; } default: { @@ -572,4 +558,27 @@ export class MediaService { return extractedSize >= targetSize; } + + private async getDevices() { + if (!this.devices) { + this.devices = await this.storageRepository.readdir('/dev/dri'); + } + + return this.devices; + } + + private async hasOpenCL() { + if (this.openCL === null) { + try { + const maliIcdStat = await this.storageRepository.stat('/etc/OpenCL/vendors/mali.icd'); + const maliDeviceStat = await this.storageRepository.stat('/dev/mali0'); + this.openCL = maliIcdStat.isFile() && maliDeviceStat.isCharacterDevice(); + } catch { + this.logger.warn('OpenCL not available for transcoding, using CPU instead.'); + this.openCL = false; + } + } + + return this.openCL; + } }