diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index df1a04dff8..6152c47218 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -2212,6 +2212,30 @@ describe(MediaService.name, () => { ); }); + it('should set hardware decoding options for rkmpp when hardware decoding is enabled with no OpenCL on non-HDR file', async () => { + storageMock.readdir.mockResolvedValue(['renderD128']); + storageMock.stat.mockResolvedValue({ isFile: () => false, isCharacterDevice: () => false } as Stats); + mediaMock.probe.mockResolvedValue(probeStub.noAudioStreams); + systemMock.get.mockResolvedValue({ + ffmpeg: { accel: TranscodeHWAccel.RKMPP, accelDecode: true, crf: 30, maxBitrate: '0' }, + }); + 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', + expect.objectContaining({ + inputOptions: expect.arrayContaining(['-hwaccel rkmpp', '-hwaccel_output_format drm_prime', '-afbc rga']), + outputOptions: expect.arrayContaining([ + expect.stringContaining( + 'scale_rkrga=-2:720:format=nv12:afbc=1', + ), + ]), + twoPass: false, + }), + ); + }); + it('should use software decoding and tone-mapping if hardware decoding is disabled', async () => { storageMock.readdir.mockResolvedValue(['renderD128']); storageMock.stat.mockResolvedValue({ isFile: () => true, isCharacterDevice: () => true } as Stats); diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index 9058d08ff6..4ef5b74676 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -502,7 +502,7 @@ export class MediaService extends BaseService { const maliDeviceStat = await this.storageRepository.stat('/dev/mali0'); this.maliOpenCL = maliIcdStat.isFile() && maliDeviceStat.isCharacterDevice(); } catch { - this.logger.debug('OpenCL not available for transcoding, so RKMPP acceleration will use CPU decoding'); + this.logger.debug('OpenCL not available for transcoding, so RKMPP acceleration will use CPU tonemapping'); this.maliOpenCL = false; } } diff --git a/server/src/utils/media.ts b/server/src/utils/media.ts index f61b472b75..978dabe95f 100644 --- a/server/src/utils/media.ts +++ b/server/src/utils/media.ts @@ -58,9 +58,8 @@ export class BaseConfig implements VideoCodecSWConfig { break; } case TranscodeHWAccel.RKMPP: { - handler = - config.accelDecode && hasMaliOpenCL - ? new RkmppHwDecodeConfig(config, devices) + handler = config.accelDecode + ? new RkmppHwDecodeConfig(config, devices, hasMaliOpenCL) : new RkmppSwDecodeConfig(config, devices); break; } @@ -968,6 +967,16 @@ export class RkmppSwDecodeConfig extends BaseHWConfig { } 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'); @@ -978,14 +987,18 @@ export class RkmppHwDecodeConfig extends RkmppSwDecodeConfig { getFilterOptions(videoStream: VideoStreamInfo) { if (this.shouldToneMap(videoStream)) { - const { primaries, transfer, matrix } = this.getColors(); - return [ - `scale_rkrga=${this.getScaling(videoStream)}:format=p010:afbc=1`, - 'hwmap=derive_device=opencl:mode=read', - `tonemap_opencl=format=nv12:r=pc:p=${primaries}:t=${transfer}:m=${matrix}:tonemap=${this.config.tonemap}:desat=0:tonemap_mode=lum:peak=100`, - 'hwmap=derive_device=rkmpp:mode=write:reverse=1', - 'format=drm_prime', - ]; + if (this.hasMaliOpenCL) { + const { primaries, transfer, matrix } = this.getColors(); + return [ + `scale_rkrga=${this.getScaling(videoStream)}:format=p010:afbc=1`, + 'hwmap=derive_device=opencl:mode=read', + `tonemap_opencl=format=nv12:r=pc:p=${primaries}:t=${transfer}:m=${matrix}:tonemap=${this.config.tonemap}:desat=0:tonemap_mode=lum:peak=100`, + 'hwmap=derive_device=rkmpp:mode=write:reverse=1', + 'format=drm_prime', + ]; + } else { + return super.getFilterOptions(videoStream); + } } else if (this.shouldScale(videoStream)) { return [`scale_rkrga=${this.getScaling(videoStream)}:format=nv12:afbc=1`]; }