mirror of
https://github.com/immich-app/immich.git
synced 2025-05-24 01:12:58 -04:00
fix(server): select main stream according to bitrate (#18375)
* fix main stream * update unit tests --------- Co-authored-by: mertalev <101130780+mertalev@users.noreply.github.com>
This commit is contained in:
parent
00a77c2d6a
commit
dc8962f2bc
@ -209,7 +209,7 @@ export class MediaRepository {
|
||||
index: stream.index,
|
||||
codecType: stream.codec_type,
|
||||
codecName: stream.codec_name,
|
||||
frameCount: this.parseInt(options?.countFrames ? stream.nb_read_packets : stream.nb_frames),
|
||||
bitrate: this.parseInt(stream.bit_rate),
|
||||
})),
|
||||
};
|
||||
}
|
||||
|
@ -1235,7 +1235,7 @@ describe(MediaService.name, () => {
|
||||
expect(mocks.media.transcode).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should transcode the longest stream', async () => {
|
||||
it('should transcode the highest bitrate video stream', async () => {
|
||||
mocks.logger.isLevelEnabled.mockReturnValue(false);
|
||||
mocks.media.probe.mockResolvedValue(probeStub.multipleVideoStreams);
|
||||
|
||||
@ -1249,7 +1249,27 @@ describe(MediaService.name, () => {
|
||||
'upload/encoded-video/user-id/as/se/asset-id.mp4',
|
||||
expect.objectContaining({
|
||||
inputOptions: expect.any(Array),
|
||||
outputOptions: expect.arrayContaining(['-map 0:0', '-map 0:1']),
|
||||
outputOptions: expect.arrayContaining(['-map 0:1', '-map 0:3']),
|
||||
twoPass: false,
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it('should transcode the highest bitrate audio stream', async () => {
|
||||
mocks.logger.isLevelEnabled.mockReturnValue(false);
|
||||
mocks.media.probe.mockResolvedValue(probeStub.multipleAudioStreams);
|
||||
|
||||
await sut.handleVideoConversion({ id: assetStub.video.id });
|
||||
|
||||
expect(mocks.media.probe).toHaveBeenCalledWith('/original/path.ext', { countFrames: false });
|
||||
expect(mocks.systemMetadata.get).toHaveBeenCalled();
|
||||
expect(mocks.storage.mkdirSync).toHaveBeenCalled();
|
||||
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(['-map 0:0', '-map 0:2']),
|
||||
twoPass: false,
|
||||
}),
|
||||
);
|
||||
@ -1780,7 +1800,7 @@ describe(MediaService.name, () => {
|
||||
'-movflags faststart',
|
||||
'-fps_mode passthrough',
|
||||
'-map 0:0',
|
||||
'-map 0:1',
|
||||
'-map 0:3',
|
||||
'-v verbose',
|
||||
'-vf scale=-2:720',
|
||||
'-preset 12',
|
||||
@ -1901,7 +1921,7 @@ describe(MediaService.name, () => {
|
||||
'-movflags faststart',
|
||||
'-fps_mode passthrough',
|
||||
'-map 0:0',
|
||||
'-map 0:1',
|
||||
'-map 0:3',
|
||||
'-g 256',
|
||||
'-v verbose',
|
||||
'-vf hwupload_cuda,scale_cuda=-2:720:format=nv12',
|
||||
@ -2072,7 +2092,7 @@ describe(MediaService.name, () => {
|
||||
'-movflags faststart',
|
||||
'-fps_mode passthrough',
|
||||
'-map 0:0',
|
||||
'-map 0:1',
|
||||
'-map 0:3',
|
||||
'-bf 7',
|
||||
'-refs 5',
|
||||
'-g 256',
|
||||
@ -2294,7 +2314,7 @@ describe(MediaService.name, () => {
|
||||
'-movflags faststart',
|
||||
'-fps_mode passthrough',
|
||||
'-map 0:0',
|
||||
'-map 0:1',
|
||||
'-map 0:3',
|
||||
'-g 256',
|
||||
'-v verbose',
|
||||
'-vf hwupload=extra_hw_frames=64,scale_vaapi=-2:720:mode=hq:out_range=pc:format=nv12',
|
||||
@ -2581,7 +2601,7 @@ describe(MediaService.name, () => {
|
||||
'-movflags faststart',
|
||||
'-fps_mode passthrough',
|
||||
'-map 0:0',
|
||||
'-map 0:1',
|
||||
'-map 0:3',
|
||||
'-g 256',
|
||||
'-v verbose',
|
||||
'-vf scale_rkrga=-2:720:format=nv12:afbc=1:async_depth=4',
|
||||
|
@ -547,7 +547,7 @@ export class MediaService extends BaseService {
|
||||
private getMainStream<T extends VideoStreamInfo | AudioStreamInfo>(streams: T[]): T {
|
||||
return streams
|
||||
.filter((stream) => stream.codecName !== 'unknown')
|
||||
.sort((stream1, stream2) => stream2.frameCount - stream1.frameCount)[0];
|
||||
.sort((stream1, stream2) => stream2.bitrate - stream1.bitrate)[0];
|
||||
}
|
||||
|
||||
private getTranscodeTarget(
|
||||
|
@ -89,7 +89,7 @@ export interface VideoStreamInfo {
|
||||
export interface AudioStreamInfo {
|
||||
index: number;
|
||||
codecName?: string;
|
||||
frameCount: number;
|
||||
bitrate: number;
|
||||
}
|
||||
|
||||
export interface VideoFormat {
|
||||
|
37
server/test/fixtures/media.stub.ts
vendored
37
server/test/fixtures/media.stub.ts
vendored
@ -21,7 +21,7 @@ const probeStubDefaultVideoStream: VideoStreamInfo[] = [
|
||||
},
|
||||
];
|
||||
|
||||
const probeStubDefaultAudioStream: AudioStreamInfo[] = [{ index: 1, codecName: 'mp3', frameCount: 100 }];
|
||||
const probeStubDefaultAudioStream: AudioStreamInfo[] = [{ index: 3, codecName: 'mp3', bitrate: 100 }];
|
||||
|
||||
const probeStubDefault: VideoInfo = {
|
||||
format: probeStubDefaultFormat,
|
||||
@ -40,23 +40,42 @@ export const probeStub = {
|
||||
height: 1080,
|
||||
width: 400,
|
||||
codecName: 'hevc',
|
||||
frameCount: 100,
|
||||
frameCount: 1,
|
||||
rotation: 0,
|
||||
isHDR: false,
|
||||
bitrate: 0,
|
||||
bitrate: 100,
|
||||
pixelFormat: 'yuv420p',
|
||||
},
|
||||
{
|
||||
index: 1,
|
||||
height: 1080,
|
||||
width: 400,
|
||||
codecName: 'h7000',
|
||||
frameCount: 99,
|
||||
codecName: 'hevc',
|
||||
frameCount: 2,
|
||||
rotation: 0,
|
||||
isHDR: false,
|
||||
bitrate: 0,
|
||||
bitrate: 101,
|
||||
pixelFormat: 'yuv420p',
|
||||
},
|
||||
{
|
||||
index: 2,
|
||||
height: 1080,
|
||||
width: 400,
|
||||
codecName: 'h7000',
|
||||
frameCount: 3,
|
||||
rotation: 0,
|
||||
isHDR: false,
|
||||
bitrate: 99,
|
||||
pixelFormat: 'yuv420p',
|
||||
},
|
||||
],
|
||||
}),
|
||||
multipleAudioStreams: Object.freeze<VideoInfo>({
|
||||
...probeStubDefault,
|
||||
audioStreams: [
|
||||
{ index: 0, codecName: 'mp3', bitrate: 100 },
|
||||
{ index: 1, codecName: 'mp3', bitrate: 101 },
|
||||
{ index: 2, codecName: 'mp3', bitrate: 102 },
|
||||
],
|
||||
}),
|
||||
noHeight: Object.freeze<VideoInfo>({
|
||||
@ -200,13 +219,13 @@ export const probeStub = {
|
||||
}),
|
||||
audioStreamAac: Object.freeze<VideoInfo>({
|
||||
...probeStubDefault,
|
||||
audioStreams: [{ index: 1, codecName: 'aac', frameCount: 100 }],
|
||||
audioStreams: [{ index: 1, codecName: 'aac', bitrate: 100 }],
|
||||
}),
|
||||
audioStreamUnknown: Object.freeze<VideoInfo>({
|
||||
...probeStubDefault,
|
||||
audioStreams: [
|
||||
{ index: 0, codecName: 'aac', frameCount: 100 },
|
||||
{ index: 1, codecName: 'unknown', frameCount: 200 },
|
||||
{ index: 0, codecName: 'aac', bitrate: 100 },
|
||||
{ index: 1, codecName: 'unknown', bitrate: 200 },
|
||||
],
|
||||
}),
|
||||
matroskaContainer: Object.freeze<VideoInfo>({
|
||||
|
Loading…
x
Reference in New Issue
Block a user