mirror of
https://github.com/immich-app/immich.git
synced 2025-06-01 04:36:19 -04:00
fix(server): set pixel format when scaling and not tonemapping (#16932)
set pixel format when scaling and not tonemapping
This commit is contained in:
parent
fe19f9ba84
commit
9f46ba8eb4
@ -1608,7 +1608,7 @@ describe(MediaService.name, () => {
|
|||||||
'upload/encoded-video/user-id/as/se/asset-id.mp4',
|
'upload/encoded-video/user-id/as/se/asset-id.mp4',
|
||||||
expect.objectContaining({
|
expect.objectContaining({
|
||||||
inputOptions: expect.arrayContaining(['-hwaccel cuda', '-hwaccel_output_format cuda']),
|
inputOptions: expect.arrayContaining(['-hwaccel cuda', '-hwaccel_output_format cuda']),
|
||||||
outputOptions: expect.arrayContaining([expect.stringContaining('format=nv12')]),
|
outputOptions: expect.arrayContaining([expect.stringContaining('scale_cuda=-2:720:format=nv12')]),
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -1766,9 +1766,7 @@ describe(MediaService.name, () => {
|
|||||||
'-threads 1',
|
'-threads 1',
|
||||||
'-qsv_device /dev/dri/renderD128',
|
'-qsv_device /dev/dri/renderD128',
|
||||||
]),
|
]),
|
||||||
outputOptions: expect.arrayContaining([
|
outputOptions: expect.arrayContaining([expect.stringContaining('scale_qsv=-1:720:async_depth=4:mode=hq')]),
|
||||||
expect.stringContaining('scale_qsv=-1:720:async_depth=4:mode=hq:format=nv12'),
|
|
||||||
]),
|
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -2010,9 +2008,7 @@ describe(MediaService.name, () => {
|
|||||||
'-threads 1',
|
'-threads 1',
|
||||||
'-hwaccel_device /dev/dri/renderD128',
|
'-hwaccel_device /dev/dri/renderD128',
|
||||||
]),
|
]),
|
||||||
outputOptions: expect.arrayContaining([
|
outputOptions: expect.arrayContaining([expect.stringContaining('scale_vaapi=-2:720:mode=hq:out_range=pc')]),
|
||||||
expect.stringContaining('scale_vaapi=-2:720:mode=hq:out_range=pc:format=nv12'),
|
|
||||||
]),
|
|
||||||
twoPass: false,
|
twoPass: false,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -2368,6 +2364,22 @@ describe(MediaService.name, () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should convert to yuv420p when scaling without tone-mapping', async () => {
|
||||||
|
mocks.media.probe.mockResolvedValue(probeStub.videoStream4K10Bit);
|
||||||
|
mocks.systemMetadata.get.mockResolvedValue({ ffmpeg: { transcode: TranscodePolicy.REQUIRED } });
|
||||||
|
mocks.asset.getByIds.mockResolvedValue([assetStub.video]);
|
||||||
|
await sut.handleVideoConversion({ id: assetStub.video.id });
|
||||||
|
expect(mocks.media.transcode).toHaveBeenCalledWith(
|
||||||
|
'/original/path.ext',
|
||||||
|
'upload/encoded-video/user-id/as/se/asset-id.mp4',
|
||||||
|
expect.objectContaining({
|
||||||
|
inputOptions: expect.any(Array),
|
||||||
|
outputOptions: expect.arrayContaining(['-c:v h264', '-c:a copy', '-vf scale=-2:720,format=yuv420p']),
|
||||||
|
twoPass: false,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
it('should count frames for progress when log level is debug', async () => {
|
it('should count frames for progress when log level is debug', async () => {
|
||||||
mocks.media.probe.mockResolvedValue(probeStub.matroskaContainer);
|
mocks.media.probe.mockResolvedValue(probeStub.matroskaContainer);
|
||||||
mocks.logger.isLevelEnabled.mockReturnValue(true);
|
mocks.logger.isLevelEnabled.mockReturnValue(true);
|
||||||
|
@ -159,9 +159,11 @@ export class BaseConfig implements VideoCodecSWConfig {
|
|||||||
options.push(`scale=${this.getScaling(videoStream)}`);
|
options.push(`scale=${this.getScaling(videoStream)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
options.push(...this.getToneMapping(videoStream));
|
const tonemapOptions = this.getToneMapping(videoStream);
|
||||||
if (options.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
|
if (tonemapOptions.length > 0) {
|
||||||
options.push(`format=yuv420p`);
|
options.push(...tonemapOptions);
|
||||||
|
} else if (!videoStream.pixelFormat.endsWith('420p')) {
|
||||||
|
options.push('format=yuv420p');
|
||||||
}
|
}
|
||||||
|
|
||||||
return options;
|
return options;
|
||||||
@ -606,14 +608,13 @@ export class NvencHwDecodeConfig extends NvencSwDecodeConfig {
|
|||||||
|
|
||||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||||
const options = [];
|
const options = [];
|
||||||
if (this.shouldScale(videoStream)) {
|
const tonemapOptions = this.getToneMapping(videoStream);
|
||||||
|
if (this.shouldScale(videoStream) || (tonemapOptions.length === 0 && !videoStream.pixelFormat.endsWith('420p'))) {
|
||||||
options.push(`scale_cuda=${this.getScaling(videoStream)}`);
|
options.push(`scale_cuda=${this.getScaling(videoStream)}`);
|
||||||
}
|
}
|
||||||
options.push(...this.getToneMapping(videoStream));
|
options.push(...tonemapOptions);
|
||||||
if (options.length > 0) {
|
if (options.length > 0) {
|
||||||
options[options.length - 1] += ':format=nv12';
|
options[options.length - 1] += ':format=nv12';
|
||||||
} else if (!videoStream.pixelFormat.endsWith('420p')) {
|
|
||||||
options.push('format=nv12');
|
|
||||||
}
|
}
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
@ -732,17 +733,12 @@ export class QsvHwDecodeConfig extends QsvSwDecodeConfig {
|
|||||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||||
const options = [];
|
const options = [];
|
||||||
const tonemapOptions = this.getToneMapping(videoStream);
|
const tonemapOptions = this.getToneMapping(videoStream);
|
||||||
if (this.shouldScale(videoStream) || tonemapOptions.length === 0) {
|
if (tonemapOptions.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
|
||||||
let scaling = `scale_qsv=${this.getScaling(videoStream)}:async_depth=4:mode=hq`;
|
options.push(`scale_qsv=${this.getScaling(videoStream)}:async_depth=4:mode=hq:format=nv12`);
|
||||||
if (tonemapOptions.length === 0) {
|
} else if (this.shouldScale(videoStream)) {
|
||||||
scaling += ':format=nv12';
|
options.push(`scale_qsv=${this.getScaling(videoStream)}:async_depth=4:mode=hq`);
|
||||||
}
|
|
||||||
options.push(scaling);
|
|
||||||
}
|
}
|
||||||
options.push(...tonemapOptions);
|
options.push(...tonemapOptions);
|
||||||
if (options.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
|
|
||||||
options.push('format=nv12');
|
|
||||||
}
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -848,17 +844,12 @@ export class VaapiHwDecodeConfig extends VaapiSwDecodeConfig {
|
|||||||
getFilterOptions(videoStream: VideoStreamInfo) {
|
getFilterOptions(videoStream: VideoStreamInfo) {
|
||||||
const options = [];
|
const options = [];
|
||||||
const tonemapOptions = this.getToneMapping(videoStream);
|
const tonemapOptions = this.getToneMapping(videoStream);
|
||||||
if (this.shouldScale(videoStream) || tonemapOptions.length === 0) {
|
if (tonemapOptions.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
|
||||||
let scaling = `scale_vaapi=${this.getScaling(videoStream)}:mode=hq:out_range=pc`;
|
options.push(`scale_vaapi=${this.getScaling(videoStream)}:mode=hq:out_range=pc:format=nv12`);
|
||||||
if (tonemapOptions.length === 0) {
|
} else if (this.shouldScale(videoStream)) {
|
||||||
scaling += ':format=nv12';
|
options.push(`scale_vaapi=${this.getScaling(videoStream)}:mode=hq:out_range=pc`);
|
||||||
}
|
|
||||||
options.push(scaling);
|
|
||||||
}
|
}
|
||||||
options.push(...tonemapOptions);
|
options.push(...tonemapOptions);
|
||||||
if (options.length === 0 && !videoStream.pixelFormat.endsWith('420p')) {
|
|
||||||
options.push('format=nv12');
|
|
||||||
}
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
server/test/fixtures/media.stub.ts
vendored
16
server/test/fixtures/media.stub.ts
vendored
@ -134,6 +134,22 @@ export const probeStub = {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
}),
|
}),
|
||||||
|
videoStream4K10Bit: Object.freeze<VideoInfo>({
|
||||||
|
...probeStubDefault,
|
||||||
|
videoStreams: [
|
||||||
|
{
|
||||||
|
index: 0,
|
||||||
|
height: 2160,
|
||||||
|
width: 3840,
|
||||||
|
codecName: 'h264',
|
||||||
|
frameCount: 100,
|
||||||
|
rotation: 0,
|
||||||
|
isHDR: false,
|
||||||
|
bitrate: 0,
|
||||||
|
pixelFormat: 'yuv420p10le',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}),
|
||||||
videoStreamVertical2160p: Object.freeze<VideoInfo>({
|
videoStreamVertical2160p: Object.freeze<VideoInfo>({
|
||||||
...probeStubDefault,
|
...probeStubDefault,
|
||||||
videoStreams: [
|
videoStreams: [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user