|
@@ -253,7 +253,10 @@ describe(MediaService.name, () => {
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
'/original/path.ext',
|
|
'/original/path.ext',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
- ['-crf 23', '-preset ultrafast', '-vcodec h264', '-acodec aac', '-movflags faststart'],
|
|
|
|
|
|
+ {
|
|
|
|
+ outputOptions: ['-vcodec h264', '-acodec aac', '-movflags faststart', '-preset ultrafast', '-crf 23'],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
);
|
|
);
|
|
});
|
|
});
|
|
|
|
|
|
@@ -276,7 +279,10 @@ describe(MediaService.name, () => {
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
'/original/path.ext',
|
|
'/original/path.ext',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
- ['-crf 23', '-preset ultrafast', '-vcodec h264', '-acodec aac', '-movflags faststart'],
|
|
|
|
|
|
+ {
|
|
|
|
+ outputOptions: ['-vcodec h264', '-acodec aac', '-movflags faststart', '-preset ultrafast', '-crf 23'],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
);
|
|
);
|
|
});
|
|
});
|
|
|
|
|
|
@@ -287,7 +293,17 @@ describe(MediaService.name, () => {
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
'/original/path.ext',
|
|
'/original/path.ext',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
- ['-crf 23', '-preset ultrafast', '-vcodec h264', '-acodec aac', '-movflags faststart', '-vf scale=-2:720'],
|
|
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec h264',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=-2:720',
|
|
|
|
+ '-preset ultrafast',
|
|
|
|
+ '-crf 23',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
);
|
|
);
|
|
});
|
|
});
|
|
|
|
|
|
@@ -298,7 +314,17 @@ describe(MediaService.name, () => {
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
'/original/path.ext',
|
|
'/original/path.ext',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
- ['-crf 23', '-preset ultrafast', '-vcodec h264', '-acodec aac', '-movflags faststart', '-vf scale=720:-2'],
|
|
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec h264',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=720:-2',
|
|
|
|
+ '-preset ultrafast',
|
|
|
|
+ '-crf 23',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
);
|
|
);
|
|
});
|
|
});
|
|
|
|
|
|
@@ -309,7 +335,17 @@ describe(MediaService.name, () => {
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
'/original/path.ext',
|
|
'/original/path.ext',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
- ['-crf 23', '-preset ultrafast', '-vcodec h264', '-acodec aac', '-movflags faststart', '-vf scale=-2:720'],
|
|
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec h264',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=-2:720',
|
|
|
|
+ '-preset ultrafast',
|
|
|
|
+ '-crf 23',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
);
|
|
);
|
|
});
|
|
});
|
|
|
|
|
|
@@ -320,7 +356,17 @@ describe(MediaService.name, () => {
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
'/original/path.ext',
|
|
'/original/path.ext',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
'upload/encoded-video/user-id/asset-id.mp4',
|
|
- ['-crf 23', '-preset ultrafast', '-vcodec h264', '-acodec aac', '-movflags faststart', '-vf scale=-2:720'],
|
|
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec h264',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=-2:720',
|
|
|
|
+ '-preset ultrafast',
|
|
|
|
+ '-crf 23',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
);
|
|
);
|
|
});
|
|
});
|
|
|
|
|
|
@@ -330,5 +376,152 @@ describe(MediaService.name, () => {
|
|
await sut.handleVideoConversion({ asset: assetEntityStub.video });
|
|
await sut.handleVideoConversion({ asset: assetEntityStub.video });
|
|
expect(mediaMock.transcode).not.toHaveBeenCalled();
|
|
expect(mediaMock.transcode).not.toHaveBeenCalled();
|
|
});
|
|
});
|
|
|
|
+
|
|
|
|
+ it('should set max bitrate if above 0', async () => {
|
|
|
|
+ mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer);
|
|
|
|
+ configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '4500k' }]);
|
|
|
|
+ await sut.handleVideoConversion({ asset: assetEntityStub.video });
|
|
|
|
+ expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
|
|
+ '/original/path.ext',
|
|
|
|
+ 'upload/encoded-video/user-id/asset-id.mp4',
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec h264',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=-2:720',
|
|
|
|
+ '-preset ultrafast',
|
|
|
|
+ '-crf 23',
|
|
|
|
+ '-maxrate 4500k',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ it('should transcode in two passes for h264/h265 when enabled and max bitrate is above 0', async () => {
|
|
|
|
+ mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer);
|
|
|
|
+ configMock.load.mockResolvedValue([
|
|
|
|
+ { key: SystemConfigKey.FFMPEG_MAX_BITRATE, value: '4500k' },
|
|
|
|
+ { key: SystemConfigKey.FFMPEG_TWO_PASS, value: true },
|
|
|
|
+ ]);
|
|
|
|
+ await sut.handleVideoConversion({ asset: assetEntityStub.video });
|
|
|
|
+ expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
|
|
+ '/original/path.ext',
|
|
|
|
+ 'upload/encoded-video/user-id/asset-id.mp4',
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec h264',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=-2:720',
|
|
|
|
+ '-preset ultrafast',
|
|
|
|
+ '-b:v 3104k',
|
|
|
|
+ '-minrate 1552k',
|
|
|
|
+ '-maxrate 4500k',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: true,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ it('should fallback to one pass for h264/h265 if two-pass is enabled but no max bitrate is set', async () => {
|
|
|
|
+ mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer);
|
|
|
|
+ configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TWO_PASS, value: true }]);
|
|
|
|
+ await sut.handleVideoConversion({ asset: assetEntityStub.video });
|
|
|
|
+ expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
|
|
+ '/original/path.ext',
|
|
|
|
+ 'upload/encoded-video/user-id/asset-id.mp4',
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec h264',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=-2:720',
|
|
|
|
+ '-preset ultrafast',
|
|
|
|
+ '-crf 23',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ it('should configure preset for vp9', async () => {
|
|
|
|
+ mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer);
|
|
|
|
+ configMock.load.mockResolvedValue([
|
|
|
|
+ { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: 'vp9' },
|
|
|
|
+ { key: SystemConfigKey.FFMPEG_THREADS, value: 2 },
|
|
|
|
+ ]);
|
|
|
|
+ await sut.handleVideoConversion({ asset: assetEntityStub.video });
|
|
|
|
+ expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
|
|
+ '/original/path.ext',
|
|
|
|
+ 'upload/encoded-video/user-id/asset-id.mp4',
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec vp9',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=-2:720',
|
|
|
|
+ '-cpu-used 5',
|
|
|
|
+ '-row-mt 1',
|
|
|
|
+ '-threads 2',
|
|
|
|
+ '-crf 23',
|
|
|
|
+ '-b:v 0',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ it('should configure threads if above 0', async () => {
|
|
|
|
+ mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer);
|
|
|
|
+ configMock.load.mockResolvedValue([
|
|
|
|
+ { key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: 'vp9' },
|
|
|
|
+ { key: SystemConfigKey.FFMPEG_THREADS, value: 2 },
|
|
|
|
+ ]);
|
|
|
|
+ await sut.handleVideoConversion({ asset: assetEntityStub.video });
|
|
|
|
+ expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
|
|
+ '/original/path.ext',
|
|
|
|
+ 'upload/encoded-video/user-id/asset-id.mp4',
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec vp9',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=-2:720',
|
|
|
|
+ '-cpu-used 5',
|
|
|
|
+ '-row-mt 1',
|
|
|
|
+ '-threads 2',
|
|
|
|
+ '-crf 23',
|
|
|
|
+ '-b:v 0',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ });
|
|
|
|
+
|
|
|
|
+ it('should disable thread pooling for x264/x265 if thread limit is above 0', async () => {
|
|
|
|
+ mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer);
|
|
|
|
+ configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_THREADS, value: 2 }]);
|
|
|
|
+ await sut.handleVideoConversion({ asset: assetEntityStub.video });
|
|
|
|
+ expect(mediaMock.transcode).toHaveBeenCalledWith(
|
|
|
|
+ '/original/path.ext',
|
|
|
|
+ 'upload/encoded-video/user-id/asset-id.mp4',
|
|
|
|
+ {
|
|
|
|
+ outputOptions: [
|
|
|
|
+ '-vcodec h264',
|
|
|
|
+ '-acodec aac',
|
|
|
|
+ '-movflags faststart',
|
|
|
|
+ '-vf scale=-2:720',
|
|
|
|
+ '-preset ultrafast',
|
|
|
|
+ '-threads 2',
|
|
|
|
+ '-x264-params "pools=none"',
|
|
|
|
+ '-x264-params "frame-threads=2"',
|
|
|
|
+ '-crf 23',
|
|
|
|
+ ],
|
|
|
|
+ twoPass: false,
|
|
|
|
+ },
|
|
|
|
+ );
|
|
|
|
+ });
|
|
});
|
|
});
|
|
});
|
|
});
|