diff --git a/server/src/repositories/media.repository.ts b/server/src/repositories/media.repository.ts index d0ced19a6e..33cf4e3e03 100644 --- a/server/src/repositories/media.repository.ts +++ b/server/src/repositories/media.repository.ts @@ -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), })), }; } diff --git a/server/src/services/media.service.spec.ts b/server/src/services/media.service.spec.ts index fa7cfc096a..3e77127aa9 100644 --- a/server/src/services/media.service.spec.ts +++ b/server/src/services/media.service.spec.ts @@ -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', diff --git a/server/src/services/media.service.ts b/server/src/services/media.service.ts index 048d03f493..5cb9d928c3 100644 --- a/server/src/services/media.service.ts +++ b/server/src/services/media.service.ts @@ -547,7 +547,7 @@ export class MediaService extends BaseService { private getMainStream(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( diff --git a/server/src/types.ts b/server/src/types.ts index d6af530216..52a5266e42 100644 --- a/server/src/types.ts +++ b/server/src/types.ts @@ -89,7 +89,7 @@ export interface VideoStreamInfo { export interface AudioStreamInfo { index: number; codecName?: string; - frameCount: number; + bitrate: number; } export interface VideoFormat { diff --git a/server/test/fixtures/media.stub.ts b/server/test/fixtures/media.stub.ts index e1579435f5..efbf21d317 100644 --- a/server/test/fixtures/media.stub.ts +++ b/server/test/fixtures/media.stub.ts @@ -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({ + ...probeStubDefault, + audioStreams: [ + { index: 0, codecName: 'mp3', bitrate: 100 }, + { index: 1, codecName: 'mp3', bitrate: 101 }, + { index: 2, codecName: 'mp3', bitrate: 102 }, ], }), noHeight: Object.freeze({ @@ -200,13 +219,13 @@ export const probeStub = { }), audioStreamAac: Object.freeze({ ...probeStubDefault, - audioStreams: [{ index: 1, codecName: 'aac', frameCount: 100 }], + audioStreams: [{ index: 1, codecName: 'aac', bitrate: 100 }], }), audioStreamUnknown: Object.freeze({ ...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({