kopia lustrzana https://github.com/mifi/lossless-cut
166 wiersze
5.2 KiB
TypeScript
166 wiersze
5.2 KiB
TypeScript
import { test, expect } from 'vitest';
|
|
|
|
import { LiteFFprobeStream, getMapStreamsArgs, getStreamIdsToCopy } from './streams';
|
|
import { FFprobeStreamDisposition } from '../../ffprobe';
|
|
|
|
|
|
const makeDisposition = (override?: Partial<FFprobeStreamDisposition>): FFprobeStreamDisposition => ({
|
|
default: 0,
|
|
dub: 0,
|
|
original: 0,
|
|
comment: 0,
|
|
lyrics: 0,
|
|
karaoke: 0,
|
|
forced: 0,
|
|
hearing_impaired: 0,
|
|
visual_impaired: 0,
|
|
clean_effects: 0,
|
|
attached_pic: 0,
|
|
timed_thumbnails: 0,
|
|
captions: 0,
|
|
descriptions: 0,
|
|
metadata: 0,
|
|
dependent: 0,
|
|
still_image: 0,
|
|
...override,
|
|
});
|
|
|
|
const streams1: LiteFFprobeStream[] = [
|
|
{ index: 0, codec_type: 'video', codec_tag: '0x0000', codec_name: 'mjpeg', disposition: makeDisposition({ attached_pic: 1 }) },
|
|
{ index: 1, codec_type: 'audio', codec_tag: '0x6134706d', codec_name: 'aac', disposition: makeDisposition() },
|
|
{ index: 2, codec_type: 'video', codec_tag: '0x31637661', codec_name: 'h264', disposition: makeDisposition() },
|
|
{ index: 3, codec_type: 'video', codec_tag: '0x0000', codec_name: 'hevc', disposition: makeDisposition() },
|
|
{ index: 4, codec_type: 'audio', codec_tag: '0x6134706d', codec_name: 'aac', disposition: makeDisposition() },
|
|
{ index: 5, codec_type: 'attachment', codec_tag: '0x0000', codec_name: 'ttf', disposition: makeDisposition() },
|
|
{ index: 6, codec_type: 'data', codec_tag: '0x64636d74', codec_name: '', disposition: makeDisposition() },
|
|
{ index: 7, codec_type: 'subtitle', codec_tag: '0x0000', codec_name: 'subrip', disposition: makeDisposition() },
|
|
];
|
|
|
|
const path = '/path/to/file';
|
|
|
|
const allFilesMeta = { [path]: { streams: streams1 } };
|
|
|
|
// Some files haven't got a valid video codec tag set, so change it to hvc1 (default by ffmpeg is hev1 which doesn't work in QuickTime)
|
|
// https://github.com/mifi/lossless-cut/issues/1032
|
|
// https://stackoverflow.com/questions/63468587/what-hevc-codec-tag-to-use-with-fmp4-hvc1-or-hev1
|
|
// https://stackoverflow.com/questions/32152090/encode-h265-to-hvc1-codec
|
|
test('getMapStreamsArgs', () => {
|
|
const outFormat = 'mp4';
|
|
|
|
expect(getMapStreamsArgs({
|
|
allFilesMeta,
|
|
copyFileStreams: [{ path, streamIds: streams1.map((stream) => stream.index) }],
|
|
outFormat,
|
|
})).toEqual([
|
|
'-map', '0:0', '-c:0', 'copy',
|
|
'-map', '0:1', '-c:1', 'copy',
|
|
'-map', '0:2', '-c:2', 'copy',
|
|
'-map', '0:3', '-c:3', 'copy', '-tag:3', 'hvc1',
|
|
'-map', '0:4', '-c:4', 'copy',
|
|
'-map', '0:5', '-c:5', 'copy',
|
|
'-map', '0:6', '-c:6', 'copy',
|
|
'-map', '0:7', '-c:7', 'mov_text',
|
|
]);
|
|
});
|
|
|
|
test('getMapStreamsArgs, subtitles to matroska', () => {
|
|
const outFormat = 'matroska';
|
|
|
|
const streams = [
|
|
{ index: 0, codec_type: 'subtitle', codec_tag: '0x67337874', codec_name: 'mov_text' },
|
|
];
|
|
|
|
expect(getMapStreamsArgs({
|
|
allFilesMeta: { [path]: { streams } },
|
|
copyFileStreams: [{ path, streamIds: streams.map((stream) => stream.index) }],
|
|
outFormat,
|
|
})).toEqual([
|
|
'-map', '0:0', '-c:0', 'srt',
|
|
]);
|
|
});
|
|
|
|
test('getMapStreamsArgs, disposition', () => {
|
|
const outFormat = 'mp4';
|
|
|
|
expect(getMapStreamsArgs({
|
|
allFilesMeta,
|
|
copyFileStreams: [{ path, streamIds: [0] }],
|
|
outFormat,
|
|
manuallyCopyDisposition: true,
|
|
})).toEqual([
|
|
'-map', '0:0',
|
|
'-c:0', 'copy',
|
|
'-disposition:0', 'attached_pic',
|
|
]);
|
|
});
|
|
|
|
test('getMapStreamsArgs, smart cut', () => {
|
|
const outFormat = 'mp4';
|
|
|
|
expect(getMapStreamsArgs({
|
|
allFilesMeta,
|
|
copyFileStreams: [{ path, streamIds: [1, 2, 4, 5, 6, 7] }], // only 1 video stream and the rest
|
|
outFormat,
|
|
manuallyCopyDisposition: true,
|
|
getVideoArgs: ({ streamIndex, outputIndex }) => {
|
|
if (streamIndex === 2) {
|
|
return [
|
|
`-c:${outputIndex}`, 'h264',
|
|
`-b:${outputIndex}`, '123456789',
|
|
];
|
|
}
|
|
return undefined;
|
|
},
|
|
})).toEqual([
|
|
'-map', '0:1',
|
|
'-c:0', 'copy',
|
|
'-map', '0:2',
|
|
'-c:1', 'h264',
|
|
'-b:1', '123456789',
|
|
'-map', '0:4',
|
|
'-c:2', 'copy',
|
|
'-map', '0:5',
|
|
'-c:3', 'copy',
|
|
'-map', '0:6',
|
|
'-c:4', 'copy',
|
|
'-map', '0:7',
|
|
'-c:5', 'mov_text',
|
|
]);
|
|
});
|
|
|
|
test('getStreamIdsToCopy, includeAllStreams false', () => {
|
|
const { streamIdsToCopy, excludedStreamIds } = getStreamIdsToCopy({ streams: streams1, includeAllStreams: false });
|
|
expect(streamIdsToCopy).toEqual([2, 1, 7]);
|
|
expect(excludedStreamIds).toEqual([0, 3, 4, 5, 6]);
|
|
});
|
|
|
|
test('srt output', () => {
|
|
expect(getMapStreamsArgs({
|
|
allFilesMeta: { [path]: { streams: [{ index: 0, codec_type: 'subtitle', codec_tag: '0x67337874', codec_name: 'mov_text' }] } },
|
|
copyFileStreams: [{ path, streamIds: [0] }],
|
|
outFormat: 'srt',
|
|
})).toEqual([
|
|
'-map', '0:0', '-c:0', 'srt',
|
|
]);
|
|
});
|
|
|
|
test('webvtt output', () => {
|
|
expect(getMapStreamsArgs({
|
|
allFilesMeta: { [path]: { streams: [{ index: 0, codec_type: 'subtitle', codec_tag: '0x67337874', codec_name: 'mov_text' }] } },
|
|
copyFileStreams: [{ path, streamIds: [0] }],
|
|
outFormat: 'webvtt',
|
|
})).toEqual([
|
|
'-map', '0:0', '-c:0', 'webvtt',
|
|
]);
|
|
});
|
|
|
|
test('ass output', () => {
|
|
expect(getMapStreamsArgs({
|
|
allFilesMeta: { [path]: { streams: [{ index: 0, codec_type: 'subtitle', codec_tag: '0x67337874', codec_name: 'mov_text' }] } },
|
|
copyFileStreams: [{ path, streamIds: [0] }],
|
|
outFormat: 'ass',
|
|
})).toEqual([
|
|
'-map', '0:0', '-c:0', 'ass',
|
|
]);
|
|
});
|