mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-09-27 02:43:48 +02:00
794 lines
24 KiB
TypeScript
794 lines
24 KiB
TypeScript
import { expect, test, vi } from 'vitest';
|
|
import { Output, OutputTrackGroup } from '../../src/output.js';
|
|
import { HLS_OUTPUT_FORMATS_DEFAULT, HlsOutputFormat } from '../../src/output-format.js';
|
|
import { NullTarget } from '../../src/target.js';
|
|
import { EncodedAudioPacketSource, EncodedVideoPacketSource } from '../../src/media-source.js';
|
|
import { HlsMuxer } from '../../src/hls/hls-muxer.js';
|
|
import { AudioCodec, VideoCodec } from '../../src/codec.js';
|
|
|
|
const videoSource = (codec: VideoCodec = 'avc') => new EncodedVideoPacketSource(codec);
|
|
const audioSource = (codec: AudioCodec = 'aac') => new EncodedAudioPacketSource(codec);
|
|
|
|
test('Playlist assignment, single video', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource());
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.groupId).toBeNull();
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
});
|
|
|
|
test('Playlist assignment, single audio', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addAudioTrack(audioSource());
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.groupId).toBeNull();
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
});
|
|
|
|
test('Playlist assignment, multiple video', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource());
|
|
output.addVideoTrack(videoSource());
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(2);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.groupId).toBeNull();
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.groupId).toBeNull();
|
|
expect(decl[1]!.references).toHaveLength(0);
|
|
});
|
|
|
|
test('Playlist assignment, multiple audio', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addAudioTrack(audioSource());
|
|
output.addAudioTrack(audioSource());
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(2);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.groupId).toBeNull();
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.groupId).toBeNull();
|
|
expect(decl[1]!.references).toHaveLength(0);
|
|
});
|
|
|
|
test('Playlist assignment, multiple video with different metadata #1', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource(), { languageCode: 'eng' });
|
|
output.addVideoTrack(videoSource(), { languageCode: 'esp' });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(3);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.groupId).toBe('video-1');
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
expect(decl[0]!.noUri).toBe(true);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.groupId).toBe('video-1');
|
|
expect(decl[1]!.references).toHaveLength(0);
|
|
expect(decl[1]!.noUri).toBe(false);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.groupId).toBeNull();
|
|
expect(decl[2]!.references).toEqual(decl.slice(0, 2));
|
|
|
|
expect(decl[2]!.playlist).toBe(decl[0]!.playlist);
|
|
});
|
|
|
|
test('Playlist assignment, multiple video with different metadata #2', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource(), { disposition: { primary: true } });
|
|
output.addVideoTrack(videoSource(), { disposition: { primary: false } });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(3);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.groupId).toBe('video-1');
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
expect(decl[0]!.noUri).toBe(true);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.groupId).toBe('video-1');
|
|
expect(decl[1]!.references).toHaveLength(0);
|
|
expect(decl[1]!.noUri).toBe(false);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.groupId).toBeNull();
|
|
expect(decl[2]!.references).toEqual(decl.slice(0, 2));
|
|
|
|
expect(decl[2]!.playlist).toBe(decl[0]!.playlist);
|
|
});
|
|
|
|
test('Playlist assignment, multiple audio with different metadata', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addAudioTrack(audioSource(), { languageCode: 'eng' });
|
|
output.addAudioTrack(audioSource(), { languageCode: 'esp' });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(3);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
expect(decl[0]!.noUri).toBe(true);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.groupId).toBe('audio-1');
|
|
expect(decl[1]!.references).toHaveLength(0);
|
|
expect(decl[1]!.noUri).toBe(false);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.groupId).toBeNull();
|
|
expect(decl[2]!.references).toEqual(decl.slice(0, 2));
|
|
|
|
expect(decl[2]!.playlist).toBe(decl[0]!.playlist);
|
|
});
|
|
|
|
test('Playlist assignment, video and audio', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource());
|
|
output.addAudioTrack(audioSource());
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(2);
|
|
expect(decl[0]!.groupId).toBeNull();
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
});
|
|
|
|
test('Playlist assignment, one video and multiple audio', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource());
|
|
output.addAudioTrack(audioSource());
|
|
output.addAudioTrack(audioSource());
|
|
output.addAudioTrack(audioSource());
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(4);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[0]!.noUri).toBe(false);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[1]!.noUri).toBe(false);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[2]!.noUri).toBe(false);
|
|
|
|
expect(decl[3]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[3]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[3]!.groupId).toBeNull();
|
|
expect(decl[3]!.references).toEqual(decl.slice(0, 3));
|
|
});
|
|
|
|
test('Playlist assignment, multiple video and one audio', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource());
|
|
output.addVideoTrack(videoSource());
|
|
output.addVideoTrack(videoSource());
|
|
output.addAudioTrack(audioSource());
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(4);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[0]!.noUri).toBe(false);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[1]!.groupId).toBeNull();
|
|
expect(decl[1]!.references).toEqual([decl[0]!]);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[2]!.groupId).toBeNull();
|
|
expect(decl[2]!.references).toEqual([decl[0]!]);
|
|
|
|
expect(decl[3]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[3]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[3]!.groupId).toBeNull();
|
|
expect(decl[3]!.references).toEqual([decl[0]!]);
|
|
});
|
|
|
|
test('Playlist assignment, multiple video and audio', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource());
|
|
output.addVideoTrack(videoSource());
|
|
output.addVideoTrack(videoSource());
|
|
output.addAudioTrack(audioSource());
|
|
output.addAudioTrack(audioSource());
|
|
output.addAudioTrack(audioSource());
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(6);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[0]!.noUri).toBe(false);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[1]!.groupId).toBe('audio-1');
|
|
expect(decl[1]!.noUri).toBe(false);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[2]!.groupId).toBe('audio-1');
|
|
expect(decl[2]!.noUri).toBe(false);
|
|
|
|
expect(decl[3]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[3]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[3]!.groupId).toBeNull();
|
|
expect(decl[3]!.references).toEqual(decl.slice(0, 3));
|
|
|
|
expect(decl[4]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[4]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[4]!.groupId).toBeNull();
|
|
expect(decl[4]!.references).toEqual(decl.slice(0, 3));
|
|
|
|
expect(decl[5]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[5]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[5]!.groupId).toBeNull();
|
|
expect(decl[5]!.references).toEqual(decl.slice(0, 3));
|
|
});
|
|
|
|
test('Playlist assignment, video and audio in different groups', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
const a = new OutputTrackGroup();
|
|
const b = new OutputTrackGroup();
|
|
|
|
output.addVideoTrack(videoSource(), { group: a });
|
|
output.addAudioTrack(audioSource(), { group: b });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(2);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[0]!.groupId).toBeNull();
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[1]!.groupId).toBeNull();
|
|
expect(decl[1]!.references).toHaveLength(0);
|
|
});
|
|
|
|
test('Playlist assignment, multiple video and audio in pairs', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
const a = new OutputTrackGroup();
|
|
const b = new OutputTrackGroup();
|
|
const c = new OutputTrackGroup();
|
|
|
|
output.addVideoTrack(videoSource(), { group: a });
|
|
output.addVideoTrack(videoSource(), { group: b });
|
|
output.addVideoTrack(videoSource(), { group: c });
|
|
output.addAudioTrack(audioSource(), { group: a });
|
|
output.addAudioTrack(audioSource(), { group: b });
|
|
output.addAudioTrack(audioSource(), { group: c });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(3);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(2);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[0]!.playlist.tracks[1]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBeNull();
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(2);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[1]!.playlist.tracks[1]!.type).toBe('audio');
|
|
expect(decl[1]!.groupId).toBeNull();
|
|
expect(decl[1]!.references).toHaveLength(0);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(2);
|
|
expect(decl[2]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[2]!.playlist.tracks[1]!.type).toBe('audio');
|
|
expect(decl[2]!.groupId).toBeNull();
|
|
expect(decl[2]!.references).toHaveLength(0);
|
|
});
|
|
|
|
test('Playlist assignment, multiple video and audio with some unpaired', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
const a = new OutputTrackGroup();
|
|
const b = new OutputTrackGroup();
|
|
const c = new OutputTrackGroup();
|
|
|
|
output.addVideoTrack(videoSource(), { group: a });
|
|
output.addVideoTrack(videoSource(), { group: a });
|
|
output.addVideoTrack(videoSource(), { group: b });
|
|
output.addAudioTrack(audioSource(), { group: a });
|
|
output.addAudioTrack(audioSource(), { group: a });
|
|
output.addAudioTrack(audioSource(), { group: c });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(6);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[0]!.noUri).toBe(false);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[1]!.groupId).toBe('audio-1');
|
|
expect(decl[1]!.noUri).toBe(false);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[2]!.groupId).toBeNull();
|
|
expect(decl[2]!.references).toEqual(decl.slice(0, 2));
|
|
|
|
expect(decl[3]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[3]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[3]!.groupId).toBeNull();
|
|
expect(decl[3]!.references).toEqual(decl.slice(0, 2));
|
|
|
|
expect(decl[4]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[4]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[4]!.groupId).toBeNull();
|
|
expect(decl[4]!.references).toHaveLength(0);
|
|
|
|
expect(decl[5]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[5]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[5]!.groupId).toBeNull();
|
|
expect(decl[5]!.references).toHaveLength(0);
|
|
});
|
|
|
|
test('Playlist assignment, multiple video and audio with multiple groups', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
const a = new OutputTrackGroup();
|
|
const b = new OutputTrackGroup();
|
|
|
|
output.addVideoTrack(videoSource(), { group: a });
|
|
output.addVideoTrack(videoSource(), { group: a });
|
|
output.addVideoTrack(videoSource(), { group: b });
|
|
output.addVideoTrack(videoSource(), { group: b });
|
|
output.addAudioTrack(audioSource(), { group: a });
|
|
output.addAudioTrack(audioSource(), { group: a });
|
|
output.addAudioTrack(audioSource(), { group: b });
|
|
output.addAudioTrack(audioSource(), { group: b });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(8);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[0]!.noUri).toBe(false);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[1]!.groupId).toBe('audio-1');
|
|
expect(decl[1]!.noUri).toBe(false);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[2]!.groupId).toBe('audio-2');
|
|
expect(decl[2]!.noUri).toBe(false);
|
|
|
|
expect(decl[3]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[3]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[3]!.groupId).toBe('audio-2');
|
|
expect(decl[3]!.noUri).toBe(false);
|
|
|
|
expect(decl[4]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[4]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[4]!.groupId).toBeNull();
|
|
expect(decl[4]!.references).toEqual(decl.slice(0, 2));
|
|
|
|
expect(decl[5]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[5]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[5]!.groupId).toBeNull();
|
|
expect(decl[5]!.references).toEqual(decl.slice(0, 2));
|
|
|
|
expect(decl[6]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[6]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[6]!.groupId).toBeNull();
|
|
expect(decl[6]!.references).toEqual(decl.slice(2, 4));
|
|
|
|
expect(decl[7]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[7]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[7]!.groupId).toBeNull();
|
|
expect(decl[7]!.references).toEqual(decl.slice(2, 4));
|
|
});
|
|
|
|
test('Playlist assignment, video with multiple audio codecs', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource());
|
|
output.addAudioTrack(audioSource('aac'));
|
|
output.addAudioTrack(audioSource('ac3'));
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(4);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.playlist.tracks[0]!.source._codec).toBe('aac');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[0]!.noUri).toBe(false);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[1]!.playlist.tracks[0]!.source._codec).toBe('ac3');
|
|
expect(decl[1]!.groupId).toBe('audio-2');
|
|
expect(decl[1]!.noUri).toBe(false);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[2]!.groupId).toBeNull();
|
|
expect(decl[2]!.references).toEqual([decl[0]!]);
|
|
|
|
expect(decl[3]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[3]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[3]!.groupId).toBeNull();
|
|
expect(decl[3]!.references).toEqual([decl[1]!]);
|
|
|
|
expect(decl[2]!.playlist).toBe(decl[3]!.playlist);
|
|
});
|
|
|
|
test('Playlist assignment, audio with multiple video codecs', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
output.addVideoTrack(videoSource('avc'));
|
|
output.addVideoTrack(videoSource('hevc'));
|
|
output.addAudioTrack(audioSource());
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(3);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[0]!.noUri).toBe(false);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[1]!.playlist.tracks[0]!.source._codec).toBe('avc');
|
|
expect(decl[1]!.groupId).toBeNull();
|
|
expect(decl[1]!.references).toEqual([decl[0]!]);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[2]!.playlist.tracks[0]!.source._codec).toBe('hevc');
|
|
expect(decl[2]!.groupId).toBeNull();
|
|
expect(decl[2]!.references).toEqual([decl[0]!]);
|
|
});
|
|
|
|
test('Playlist assignment, multiple video with conflicting audio interests', async () => {
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
const a = new OutputTrackGroup();
|
|
const b = new OutputTrackGroup();
|
|
|
|
output.addVideoTrack(videoSource(), { group: a });
|
|
output.addVideoTrack(videoSource(), { group: b });
|
|
output.addAudioTrack(audioSource(), { group: [a, b] });
|
|
output.addAudioTrack(audioSource(), { group: a });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(5);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[0]!.groupId).toBe('audio-1');
|
|
expect(decl[0]!.noUri).toBe(false);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[1]!.groupId).toBe('audio-1');
|
|
expect(decl[1]!.noUri).toBe(false);
|
|
|
|
expect(decl[2]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[2]!.playlist.tracks[0]!.type).toBe('audio');
|
|
expect(decl[2]!.playlist).toBe(decl[0]!.playlist);
|
|
expect(decl[2]!.groupId).toBe('audio-2');
|
|
expect(decl[2]!.noUri).toBe(false);
|
|
|
|
expect(decl[3]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[3]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[3]!.groupId).toBeNull();
|
|
expect(decl[3]!.references).toEqual([decl[0]!, decl[1]!]);
|
|
|
|
expect(decl[4]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[4]!.playlist.tracks[0]!.type).toBe('video');
|
|
expect(decl[4]!.groupId).toBeNull();
|
|
expect(decl[4]!.references).toEqual([decl[2]!]);
|
|
});
|
|
|
|
test('Playlist assignment, video paired with video', async () => {
|
|
const consoleSpy = vi.spyOn(console, 'warn');
|
|
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
const a = new OutputTrackGroup();
|
|
const b = new OutputTrackGroup();
|
|
a.pairWith(b);
|
|
|
|
output.addVideoTrack(videoSource(), { group: a });
|
|
output.addVideoTrack(videoSource(), { group: b });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(2);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.groupId).toBeNull();
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.groupId).toBeNull();
|
|
expect(decl[1]!.references).toHaveLength(0);
|
|
|
|
expect(consoleSpy.mock.calls).toHaveLength(1);
|
|
expect(consoleSpy.mock.calls[0]![0]).toContain('Illegal pairing');
|
|
});
|
|
|
|
test('Playlist assignment, audio paired with audio', async () => {
|
|
const consoleSpy = vi.spyOn(console, 'warn');
|
|
|
|
const output = new Output({
|
|
format: new HlsOutputFormat({
|
|
segmentFormats: HLS_OUTPUT_FORMATS_DEFAULT,
|
|
}),
|
|
target: () => new NullTarget(),
|
|
rootPath: '',
|
|
});
|
|
|
|
const a = new OutputTrackGroup();
|
|
const b = new OutputTrackGroup();
|
|
a.pairWith(b);
|
|
|
|
output.addAudioTrack(audioSource(), { group: a });
|
|
output.addAudioTrack(audioSource(), { group: b });
|
|
|
|
await output.start();
|
|
|
|
const muxer = output._muxer as HlsMuxer;
|
|
const decl = muxer.playlistDeclarations;
|
|
|
|
expect(decl).toHaveLength(2);
|
|
|
|
expect(decl[0]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[0]!.groupId).toBeNull();
|
|
expect(decl[0]!.references).toHaveLength(0);
|
|
|
|
expect(decl[1]!.playlist.tracks).toHaveLength(1);
|
|
expect(decl[1]!.groupId).toBeNull();
|
|
expect(decl[1]!.references).toHaveLength(0);
|
|
|
|
expect(consoleSpy.mock.calls).toHaveLength(1);
|
|
expect(consoleSpy.mock.calls[0]![0]).toContain('Illegal pairing');
|
|
});
|