fix(server): hevc tag being set when copying a non-hevc stream (#8582)

This commit is contained in:
Mert 2024-04-07 12:44:09 -04:00 committed by GitHub
parent 0d130b8957
commit 55b9acca78
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 74 additions and 3 deletions

View File

@ -747,6 +747,67 @@ describe(MediaService.name, () => {
);
});
it('should not include hevc tag when target is hevc and video stream is copied from a different codec', async () => {
mediaMock.probe.mockResolvedValue(probeStub.videoStreamH264);
configMock.load.mockResolvedValue([
{ key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.HEVC },
{ key: SystemConfigKey.FFMPEG_ACCEPTED_VIDEO_CODECS, value: [VideoCodec.H264, VideoCodec.HEVC] },
{ key: SystemConfigKey.FFMPEG_ACCEPTED_AUDIO_CODECS, value: [AudioCodec.AAC] },
]);
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',
{
inputOptions: [],
outputOptions: [
'-c:v copy',
'-c:a aac',
'-movflags faststart',
'-fps_mode passthrough',
'-map 0:0',
'-map 0:1',
'-v verbose',
'-preset ultrafast',
'-crf 23',
],
twoPass: false,
},
);
});
it('should include hevc tag when target is hevc and copying hevc video stream', async () => {
mediaMock.probe.mockResolvedValue(probeStub.matroskaContainer);
configMock.load.mockResolvedValue([
{ key: SystemConfigKey.FFMPEG_TARGET_VIDEO_CODEC, value: VideoCodec.HEVC },
{ key: SystemConfigKey.FFMPEG_ACCEPTED_VIDEO_CODECS, value: [VideoCodec.H264, VideoCodec.HEVC] },
{ key: SystemConfigKey.FFMPEG_ACCEPTED_AUDIO_CODECS, value: [AudioCodec.AAC] },
]);
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',
{
inputOptions: [],
outputOptions: [
'-c:v copy',
'-c:a aac',
'-movflags faststart',
'-fps_mode passthrough',
'-map 0:0',
'-map 0:1',
'-tag:v hvc1',
'-v verbose',
'-preset ultrafast',
'-crf 23',
],
twoPass: false,
},
);
});
it('should copy audio stream when audio matches target', async () => {
mediaMock.probe.mockResolvedValue(probeStub.audioStreamAac);
configMock.load.mockResolvedValue([{ key: SystemConfigKey.FFMPEG_TRANSCODE, value: TranscodePolicy.OPTIMAL }]);

View File

@ -37,9 +37,12 @@ class BaseConfig implements VideoCodecSWConfig {
}
getBaseOutputOptions(target: TranscodeTarget, videoStream: VideoStreamInfo, audioStream?: AudioStreamInfo) {
const videoCodec = [TranscodeTarget.ALL, TranscodeTarget.VIDEO].includes(target) ? this.getVideoCodec() : 'copy';
const audioCodec = [TranscodeTarget.ALL, TranscodeTarget.AUDIO].includes(target) ? this.getAudioCodec() : 'copy';
const options = [
`-c:v ${[TranscodeTarget.ALL, TranscodeTarget.VIDEO].includes(target) ? this.getVideoCodec() : 'copy'}`,
`-c:a ${[TranscodeTarget.ALL, TranscodeTarget.AUDIO].includes(target) ? this.getAudioCodec() : 'copy'}`,
`-c:v ${videoCodec}`,
`-c:a ${audioCodec}`,
// Makes a second pass moving the moov atom to the
// beginning of the file for improved playback speed.
'-movflags faststart',
@ -61,7 +64,10 @@ class BaseConfig implements VideoCodecSWConfig {
options.push(`-g ${this.getGopSize()}`);
}
if (this.config.targetVideoCodec === VideoCodec.HEVC) {
if (
this.config.targetVideoCodec === VideoCodec.HEVC &&
(videoCodec !== 'copy' || videoStream.codecName === 'hevc')
) {
options.push('-tag:v hvc1');
}

View File

@ -173,4 +173,8 @@ export const probeStub = {
bitrate: 0,
},
}),
videoStreamH264: Object.freeze<VideoInfo>({
...probeStubDefault,
videoStreams: [{ ...probeStubDefaultVideoStream[0], codecName: 'h264' }],
}),
};