mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-10 09:13:47 +02:00
Remove InputTrack.groupId, hide pairing mask, change HLS track merging behavior
This commit is contained in:
@@ -215,10 +215,6 @@ class AdtsAudioTrackBacking implements InputAudioTrackBacking {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId() {
|
|
||||||
return this.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask() {
|
getPairingMask() {
|
||||||
return 1n;
|
return 1n;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -602,10 +602,6 @@ class FlacAudioTrackBacking implements InputAudioTrackBacking {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId() {
|
|
||||||
return this.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask() {
|
getPairingMask() {
|
||||||
return 1n;
|
return 1n;
|
||||||
}
|
}
|
||||||
|
|||||||
+27
-22
@@ -30,7 +30,6 @@ type InternalTrack = {
|
|||||||
|
|
||||||
fullPath: string;
|
fullPath: string;
|
||||||
fullCodecString: string;
|
fullCodecString: string;
|
||||||
groupId: number;
|
|
||||||
pairingMask: bigint;
|
pairingMask: bigint;
|
||||||
peakBitrate: number | null;
|
peakBitrate: number | null;
|
||||||
averageBitrate: number | null;
|
averageBitrate: number | null;
|
||||||
@@ -179,7 +178,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
// Now, let's process & resolve all variant streams in parallel, mapping each of them to tracks.
|
// Now, let's process & resolve all variant streams in parallel, mapping each of them to tracks.
|
||||||
|
|
||||||
const internalTracksByVariant = await Promise.all(variantStreams.map(async (variantStream, i) => {
|
const internalTracksByVariant = await Promise.all(variantStreams.map(async (variantStream, i) => {
|
||||||
const result: { track: InternalTrack; canMerge: boolean }[] = [];
|
const result: InternalTrack[] = [];
|
||||||
|
|
||||||
const codecsList = variantStream.attributes.get('codecs');
|
const codecsList = variantStream.attributes.get('codecs');
|
||||||
let codecStrings: string[];
|
let codecStrings: string[];
|
||||||
@@ -334,7 +333,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push({ track: {
|
result.push({
|
||||||
id: -1,
|
id: -1,
|
||||||
demuxer: this,
|
demuxer: this,
|
||||||
inputTrack: null,
|
inputTrack: null,
|
||||||
@@ -345,7 +344,6 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
lineNumber: variantStream.lineNumber,
|
lineNumber: variantStream.lineNumber,
|
||||||
fullPath: variantStream.fullPath,
|
fullPath: variantStream.fullPath,
|
||||||
fullCodecString: videoCodecString,
|
fullCodecString: videoCodecString,
|
||||||
groupId: 1,
|
|
||||||
pairingMask: 1n << BigInt(i),
|
pairingMask: 1n << BigInt(i),
|
||||||
peakBitrate: bandwidth,
|
peakBitrate: bandwidth,
|
||||||
averageBitrate: averageBandwidth,
|
averageBitrate: averageBandwidth,
|
||||||
@@ -356,7 +354,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
},
|
},
|
||||||
}, canMerge: false });
|
});
|
||||||
} else {
|
} else {
|
||||||
if (!videoGroupIds.includes(videoGroupId)) {
|
if (!videoGroupIds.includes(videoGroupId)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -386,7 +384,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push({ track: {
|
result.push({
|
||||||
id: -1,
|
id: -1,
|
||||||
demuxer: this,
|
demuxer: this,
|
||||||
inputTrack: null,
|
inputTrack: null,
|
||||||
@@ -399,7 +397,6 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
lineNumber: mediaTag.lineNumber,
|
lineNumber: mediaTag.lineNumber,
|
||||||
fullPath: mediaTag.fullPath ?? variantStream.fullPath,
|
fullPath: mediaTag.fullPath ?? variantStream.fullPath,
|
||||||
fullCodecString: videoCodecString,
|
fullCodecString: videoCodecString,
|
||||||
groupId: 3 + videoGroupIds.indexOf(groupId),
|
|
||||||
pairingMask: 1n << BigInt(i),
|
pairingMask: 1n << BigInt(i),
|
||||||
peakBitrate: null,
|
peakBitrate: null,
|
||||||
averageBitrate: null,
|
averageBitrate: null,
|
||||||
@@ -410,7 +407,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
},
|
},
|
||||||
}, canMerge: true });
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (AUDIO_CODECS.includes(inferredCodec as AudioCodec)) {
|
} else if (AUDIO_CODECS.includes(inferredCodec as AudioCodec)) {
|
||||||
@@ -431,7 +428,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
? Number(channels)
|
? Number(channels)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
result.push({ track: {
|
result.push({
|
||||||
id: -1,
|
id: -1,
|
||||||
demuxer: this,
|
demuxer: this,
|
||||||
inputTrack: null,
|
inputTrack: null,
|
||||||
@@ -442,7 +439,6 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
lineNumber: variantStream.lineNumber,
|
lineNumber: variantStream.lineNumber,
|
||||||
fullPath: variantStream.fullPath,
|
fullPath: variantStream.fullPath,
|
||||||
fullCodecString: audioCodecString,
|
fullCodecString: audioCodecString,
|
||||||
groupId: 2,
|
|
||||||
pairingMask: 1n << BigInt(i),
|
pairingMask: 1n << BigInt(i),
|
||||||
peakBitrate: bandwidth,
|
peakBitrate: bandwidth,
|
||||||
averageBitrate: averageBandwidth,
|
averageBitrate: averageBandwidth,
|
||||||
@@ -457,7 +453,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
? parsedChannels
|
? parsedChannels
|
||||||
: null,
|
: null,
|
||||||
},
|
},
|
||||||
}, canMerge: false });
|
});
|
||||||
} else {
|
} else {
|
||||||
if (!audioGroupIds.includes(audioGroupId)) {
|
if (!audioGroupIds.includes(audioGroupId)) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@@ -480,7 +476,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
? Number(channels)
|
? Number(channels)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
result.push({ track: {
|
result.push({
|
||||||
id: -1,
|
id: -1,
|
||||||
demuxer: this,
|
demuxer: this,
|
||||||
inputTrack: null,
|
inputTrack: null,
|
||||||
@@ -493,7 +489,6 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
lineNumber: mediaTag.lineNumber,
|
lineNumber: mediaTag.lineNumber,
|
||||||
fullPath: mediaTag.fullPath ?? variantStream.fullPath,
|
fullPath: mediaTag.fullPath ?? variantStream.fullPath,
|
||||||
fullCodecString: audioCodecString,
|
fullCodecString: audioCodecString,
|
||||||
groupId: 3 + videoGroupIds.length + audioGroupIds.indexOf(groupId),
|
|
||||||
pairingMask: 1n << BigInt(i),
|
pairingMask: 1n << BigInt(i),
|
||||||
peakBitrate: null,
|
peakBitrate: null,
|
||||||
averageBitrate: null,
|
averageBitrate: null,
|
||||||
@@ -508,7 +503,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
? parsedChannels
|
? parsedChannels
|
||||||
: null,
|
: null,
|
||||||
},
|
},
|
||||||
}, canMerge: true });
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -518,16 +513,30 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const internalTracks: InternalTrack[] = [];
|
const internalTracks: InternalTrack[] = [];
|
||||||
const addInternalTrack = (track: InternalTrack, canMerge: boolean) => {
|
const addInternalTrack = (track: InternalTrack) => {
|
||||||
const existingTrack = internalTracks.find(x =>
|
const existingTrack = internalTracks.find(x =>
|
||||||
x.fullPath === track.fullPath && x.info.type === track.info.type && x.groupId === track.groupId,
|
x.fullPath === track.fullPath && x.info.type === track.info.type,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (existingTrack && canMerge) {
|
if (existingTrack) {
|
||||||
existingTrack.pairingMask |= track.pairingMask;
|
existingTrack.pairingMask |= track.pairingMask;
|
||||||
existingTrack.default ||= track.default;
|
existingTrack.default ||= track.default;
|
||||||
|
existingTrack.autoselect ||= track.autoselect;
|
||||||
existingTrack.lineNumber = Math.min(existingTrack.lineNumber, track.lineNumber);
|
existingTrack.lineNumber = Math.min(existingTrack.lineNumber, track.lineNumber);
|
||||||
|
|
||||||
|
if (track.peakBitrate !== null) {
|
||||||
|
existingTrack.peakBitrate = Math.max(
|
||||||
|
existingTrack.peakBitrate ?? -Infinity,
|
||||||
|
track.peakBitrate,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (track.averageBitrate !== null) {
|
||||||
|
existingTrack.averageBitrate = Math.max(
|
||||||
|
existingTrack.averageBitrate ?? -Infinity,
|
||||||
|
track.averageBitrate,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
if (existingTrack.languageCode === UNDETERMINED_LANGUAGE) {
|
if (existingTrack.languageCode === UNDETERMINED_LANGUAGE) {
|
||||||
existingTrack.languageCode = track.languageCode;
|
existingTrack.languageCode = track.languageCode;
|
||||||
}
|
}
|
||||||
@@ -539,7 +548,7 @@ export class HlsDemuxer extends Demuxer {
|
|||||||
|
|
||||||
for (const variantInternalTracks of internalTracksByVariant) {
|
for (const variantInternalTracks of internalTracksByVariant) {
|
||||||
for (const trackEntry of variantInternalTracks) {
|
for (const trackEntry of variantInternalTracks) {
|
||||||
addInternalTrack(trackEntry.track, trackEntry.canMerge);
|
addInternalTrack(trackEntry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -653,10 +662,6 @@ abstract class HlsInputTrackBacking implements InputTrackBacking {
|
|||||||
return this.internalTrack.id;
|
return this.internalTrack.id;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId(): number {
|
|
||||||
return this.internalTrack.groupId;
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask(): bigint {
|
getPairingMask(): bigint {
|
||||||
return this.internalTrack.pairingMask;
|
return this.internalTrack.pairingMask;
|
||||||
}
|
}
|
||||||
|
|||||||
+11
-27
@@ -2,7 +2,15 @@ import { MediaCodec, validateAudioChunkMetadata, validateVideoChunkMetadata } fr
|
|||||||
import { EncodedAudioPacketSource, EncodedVideoPacketSource, MediaSource } from '../media-source';
|
import { EncodedAudioPacketSource, EncodedVideoPacketSource, MediaSource } from '../media-source';
|
||||||
import { assert, joinPaths, textEncoder, UNDETERMINED_LANGUAGE } from '../misc';
|
import { assert, joinPaths, textEncoder, UNDETERMINED_LANGUAGE } from '../misc';
|
||||||
import { Muxer } from '../muxer';
|
import { Muxer } from '../muxer';
|
||||||
import { Output, OutputAudioTrack, OutputSubtitleTrack, OutputTrack, OutputVideoTrack, TrackType } from '../output';
|
import {
|
||||||
|
Output,
|
||||||
|
OutputAudioTrack,
|
||||||
|
OutputSubtitleTrack,
|
||||||
|
OutputTrack,
|
||||||
|
outputTracksArePairable,
|
||||||
|
OutputVideoTrack,
|
||||||
|
TrackType,
|
||||||
|
} from '../output';
|
||||||
import { HlsOutputFormat, HlsOutputFormatOptions, OutputFormat } from '../output-format';
|
import { HlsOutputFormat, HlsOutputFormatOptions, OutputFormat } from '../output-format';
|
||||||
import { EncodedPacket } from '../packet';
|
import { EncodedPacket } from '../packet';
|
||||||
import { SubtitleCue, SubtitleMetadata } from '../subtitles';
|
import { SubtitleCue, SubtitleMetadata } from '../subtitles';
|
||||||
@@ -101,38 +109,13 @@ export class HlsMuxer extends Muxer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const pairableGroups = new Map<MediaCodec, OutputTrack[]>();
|
const pairableGroups = new Map<MediaCodec, OutputTrack[]>();
|
||||||
const trackGroups = Array.isArray(track.metadata.group)
|
|
||||||
? track.metadata.group
|
|
||||||
: [track.metadata.group!];
|
|
||||||
|
|
||||||
for (const otherTrack of this.output._tracks) {
|
for (const otherTrack of this.output._tracks) {
|
||||||
if (track === otherTrack) {
|
if (track === otherTrack) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let pairable = false;
|
if (!outputTracksArePairable(track, otherTrack)) {
|
||||||
const otherTrackGroups = Array.isArray(otherTrack.metadata.group)
|
|
||||||
? otherTrack.metadata.group
|
|
||||||
: [otherTrack.metadata.group!];
|
|
||||||
|
|
||||||
for (const group of trackGroups) {
|
|
||||||
const pairableInSameGroup = track.type !== otherTrack.type
|
|
||||||
&& otherTrackGroups.some(otherGroup => group === otherGroup);
|
|
||||||
if (pairableInSameGroup) {
|
|
||||||
pairable = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
const pairableAcrossGroups = otherTrackGroups.some(
|
|
||||||
otherGroup => group._pairedGroups.has(otherGroup),
|
|
||||||
);
|
|
||||||
if (pairableAcrossGroups) {
|
|
||||||
pairable = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pairable) {
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -828,6 +811,7 @@ export class HlsMuxer extends Muxer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Write all playlists in parallel
|
||||||
const playlistPromises = this.playlists.map(async (playlist) => {
|
const playlistPromises = this.playlists.map(async (playlist) => {
|
||||||
let targetDuration = this.targetSegmentDuration;
|
let targetDuration = this.targetSegmentDuration;
|
||||||
for (const segment of playlist.writtenSegments) {
|
for (const segment of playlist.writtenSegments) {
|
||||||
|
|||||||
+5
-12
@@ -41,7 +41,6 @@ export interface InputTrackBacking {
|
|||||||
getTimeResolution(): number;
|
getTimeResolution(): number;
|
||||||
getTimestampsAreRelativeToUnixEpoch(): boolean;
|
getTimestampsAreRelativeToUnixEpoch(): boolean;
|
||||||
getDisposition(): TrackDisposition;
|
getDisposition(): TrackDisposition;
|
||||||
getGroupId(): number;
|
|
||||||
getPairingMask(): bigint;
|
getPairingMask(): bigint;
|
||||||
getBitrate(): number | null;
|
getBitrate(): number | null;
|
||||||
getAverageBitrate(): number | null;
|
getAverageBitrate(): number | null;
|
||||||
@@ -118,14 +117,6 @@ export abstract class InputTrack {
|
|||||||
return this._backing.getNumber();
|
return this._backing.getNumber();
|
||||||
}
|
}
|
||||||
|
|
||||||
get groupId() {
|
|
||||||
return this._backing.getGroupId();
|
|
||||||
}
|
|
||||||
|
|
||||||
get pairingMask() {
|
|
||||||
return this._backing.getPairingMask();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The identifier of the codec used internally by the container. It is not homogenized by Mediabunny
|
* The identifier of the codec used internally by the container. It is not homogenized by Mediabunny
|
||||||
* and depends entirely on the container format.
|
* and depends entirely on the container format.
|
||||||
@@ -310,9 +301,11 @@ export abstract class InputTrack {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.input === otherTrack.input
|
if (this.input !== otherTrack.input || this === otherTrack) {
|
||||||
&& this.groupId !== otherTrack.groupId // This also prevents the track from being paired with itself
|
return false;
|
||||||
&& (this.pairingMask & otherTrack.pairingMask) !== 0n;
|
}
|
||||||
|
|
||||||
|
return (this._backing.getPairingMask() & otherTrack._backing.getPairingMask()) !== 0n;
|
||||||
}
|
}
|
||||||
|
|
||||||
async getPairableTracks(query?: TrackQuery<InputTrack>) {
|
async getPairableTracks(query?: TrackQuery<InputTrack>) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ import {
|
|||||||
InputAudioTrackBacking,
|
InputAudioTrackBacking,
|
||||||
InputTrack,
|
InputTrack,
|
||||||
InputTrackBacking,
|
InputTrackBacking,
|
||||||
|
|
||||||
InputVideoTrack,
|
InputVideoTrack,
|
||||||
InputVideoTrackBacking,
|
InputVideoTrackBacking,
|
||||||
} from '../input-track';
|
} from '../input-track';
|
||||||
@@ -2565,10 +2566,6 @@ abstract class IsobmffTrackBacking implements InputTrackBacking {
|
|||||||
return this.internalTrack.disposition;
|
return this.internalTrack.disposition;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId() {
|
|
||||||
return this.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask() {
|
getPairingMask() {
|
||||||
return 1n;
|
return 1n;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import {
|
|||||||
InputAudioTrackBacking,
|
InputAudioTrackBacking,
|
||||||
InputTrack,
|
InputTrack,
|
||||||
InputTrackBacking,
|
InputTrackBacking,
|
||||||
|
|
||||||
InputVideoTrack,
|
InputVideoTrack,
|
||||||
InputVideoTrackBacking,
|
InputVideoTrackBacking,
|
||||||
} from '../input-track';
|
} from '../input-track';
|
||||||
@@ -1978,10 +1979,6 @@ abstract class MatroskaTrackBacking implements InputTrackBacking {
|
|||||||
return this.internalTrack.disposition;
|
return this.internalTrack.disposition;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId() {
|
|
||||||
return this.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask() {
|
getPairingMask() {
|
||||||
return 1n;
|
return 1n;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -293,10 +293,6 @@ class Mp3AudioTrackBacking implements InputAudioTrackBacking {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId() {
|
|
||||||
return this.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask() {
|
getPairingMask() {
|
||||||
return 1n;
|
return 1n;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import {
|
|||||||
InputAudioTrackBacking,
|
InputAudioTrackBacking,
|
||||||
InputTrack,
|
InputTrack,
|
||||||
InputTrackBacking,
|
InputTrackBacking,
|
||||||
|
|
||||||
InputVideoTrack,
|
InputVideoTrack,
|
||||||
InputVideoTrackBacking,
|
InputVideoTrackBacking,
|
||||||
} from '../input-track';
|
} from '../input-track';
|
||||||
@@ -1099,10 +1100,6 @@ abstract class MpegTsTrackBacking implements InputTrackBacking {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId() {
|
|
||||||
return this.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask() {
|
getPairingMask() {
|
||||||
return 1n;
|
return 1n;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -452,10 +452,6 @@ class OggAudioTrackBacking implements InputAudioTrackBacking {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId() {
|
|
||||||
return this.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask() {
|
getPairingMask() {
|
||||||
return 1n;
|
return 1n;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -83,6 +83,36 @@ export class OutputTrackGroup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const outputTracksArePairable = (a: OutputTrack, b: OutputTrack) => {
|
||||||
|
if (a === b) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const aGroups = Array.isArray(a.metadata.group)
|
||||||
|
? a.metadata.group
|
||||||
|
: [a.metadata.group!];
|
||||||
|
const bGroups = Array.isArray(b.metadata.group)
|
||||||
|
? b.metadata.group
|
||||||
|
: [b.metadata.group!];
|
||||||
|
|
||||||
|
for (const aGroup of aGroups) {
|
||||||
|
const pairableInSameGroup = a.type !== b.type
|
||||||
|
&& bGroups.some(bGroup => aGroup === bGroup);
|
||||||
|
if (pairableInSameGroup) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pairableAcrossGroups = bGroups.some(
|
||||||
|
bGroup => aGroup._pairedGroups.has(bGroup),
|
||||||
|
);
|
||||||
|
if (pairableAcrossGroups) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Base track metadata, applicable to all tracks.
|
* Base track metadata, applicable to all tracks.
|
||||||
* @group Output files
|
* @group Output files
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
InputAudioTrackBacking,
|
InputAudioTrackBacking,
|
||||||
InputTrack,
|
InputTrack,
|
||||||
InputTrackBacking,
|
InputTrackBacking,
|
||||||
|
|
||||||
InputVideoTrack,
|
InputVideoTrack,
|
||||||
InputVideoTrackBacking,
|
InputVideoTrackBacking,
|
||||||
} from './input-track';
|
} from './input-track';
|
||||||
@@ -222,11 +223,7 @@ class SegmentedInputInputTrackBacking implements InputTrackBacking {
|
|||||||
return this.firstInputTrack._backing.getId();
|
return this.firstInputTrack._backing.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId(): number {
|
getPairingMask() {
|
||||||
return this.firstInputTrack._backing.getGroupId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask(): bigint {
|
|
||||||
return this.firstInputTrack._backing.getPairingMask();
|
return this.firstInputTrack._backing.getPairingMask();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -405,10 +405,6 @@ class WaveAudioTrackBacking implements InputAudioTrackBacking {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
getGroupId() {
|
|
||||||
return this.getId();
|
|
||||||
}
|
|
||||||
|
|
||||||
getPairingMask() {
|
getPairingMask() {
|
||||||
return 1n;
|
return 1n;
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-150
@@ -36,8 +36,6 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(videoTracks[0]!.displayHeight).toBe(720);
|
expect(videoTracks[0]!.displayHeight).toBe(720);
|
||||||
expect(videoTracks[0]!.bitrate).toBe(2149280);
|
expect(videoTracks[0]!.bitrate).toBe(2149280);
|
||||||
expect(videoTracks[0]!.name).toBe('720');
|
expect(videoTracks[0]!.name).toBe('720');
|
||||||
expect(videoTracks[0]!.groupId).toBe(1);
|
|
||||||
expect(videoTracks[0]!.pairingMask).toBe(1n << 0n);
|
|
||||||
expect(videoTracks[0]!.isHydrated).toBe(false);
|
expect(videoTracks[0]!.isHydrated).toBe(false);
|
||||||
expect(videoTracks[0]!.id).toBe(2);
|
expect(videoTracks[0]!.id).toBe(2);
|
||||||
expect(() => videoTracks[0]?.codedWidth).toThrow();
|
expect(() => videoTracks[0]?.codedWidth).toThrow();
|
||||||
@@ -48,8 +46,6 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(videoTracks[1]!.displayHeight).toBe(184);
|
expect(videoTracks[1]!.displayHeight).toBe(184);
|
||||||
expect(videoTracks[1]!.bitrate).toBe(246440);
|
expect(videoTracks[1]!.bitrate).toBe(246440);
|
||||||
expect(videoTracks[1]!.name).toBe('240');
|
expect(videoTracks[1]!.name).toBe('240');
|
||||||
expect(videoTracks[1]!.groupId).toBe(1);
|
|
||||||
expect(videoTracks[1]!.pairingMask).toBe(1n << 1n);
|
|
||||||
expect(videoTracks[1]!.isHydrated).toBe(false);
|
expect(videoTracks[1]!.isHydrated).toBe(false);
|
||||||
expect(videoTracks[1]!.id).toBe(4);
|
expect(videoTracks[1]!.id).toBe(4);
|
||||||
|
|
||||||
@@ -59,8 +55,6 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(videoTracks[2]!.displayHeight).toBe(288);
|
expect(videoTracks[2]!.displayHeight).toBe(288);
|
||||||
expect(videoTracks[2]!.bitrate).toBe(460560);
|
expect(videoTracks[2]!.bitrate).toBe(460560);
|
||||||
expect(videoTracks[2]!.name).toBe('380');
|
expect(videoTracks[2]!.name).toBe('380');
|
||||||
expect(videoTracks[2]!.groupId).toBe(1);
|
|
||||||
expect(videoTracks[2]!.pairingMask).toBe(1n << 2n);
|
|
||||||
expect(videoTracks[2]!.isHydrated).toBe(false);
|
expect(videoTracks[2]!.isHydrated).toBe(false);
|
||||||
expect(videoTracks[2]!.id).toBe(6);
|
expect(videoTracks[2]!.id).toBe(6);
|
||||||
|
|
||||||
@@ -70,8 +64,6 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(videoTracks[3]!.displayHeight).toBe(480);
|
expect(videoTracks[3]!.displayHeight).toBe(480);
|
||||||
expect(videoTracks[3]!.bitrate).toBe(836280);
|
expect(videoTracks[3]!.bitrate).toBe(836280);
|
||||||
expect(videoTracks[3]!.name).toBe('480');
|
expect(videoTracks[3]!.name).toBe('480');
|
||||||
expect(videoTracks[3]!.groupId).toBe(1);
|
|
||||||
expect(videoTracks[3]!.pairingMask).toBe(1n << 3n);
|
|
||||||
expect(videoTracks[3]!.isHydrated).toBe(false);
|
expect(videoTracks[3]!.isHydrated).toBe(false);
|
||||||
expect(videoTracks[3]!.id).toBe(8);
|
expect(videoTracks[3]!.id).toBe(8);
|
||||||
|
|
||||||
@@ -81,8 +73,6 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(videoTracks[4]!.displayHeight).toBe(1080);
|
expect(videoTracks[4]!.displayHeight).toBe(1080);
|
||||||
expect(videoTracks[4]!.bitrate).toBe(6221600);
|
expect(videoTracks[4]!.bitrate).toBe(6221600);
|
||||||
expect(videoTracks[4]!.name).toBe('1080');
|
expect(videoTracks[4]!.name).toBe('1080');
|
||||||
expect(videoTracks[4]!.groupId).toBe(1);
|
|
||||||
expect(videoTracks[4]!.pairingMask).toBe(1n << 4n);
|
|
||||||
expect(videoTracks[4]!.isHydrated).toBe(false);
|
expect(videoTracks[4]!.isHydrated).toBe(false);
|
||||||
expect(videoTracks[4]!.id).toBe(10);
|
expect(videoTracks[4]!.id).toBe(10);
|
||||||
|
|
||||||
@@ -90,8 +80,6 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(await audioTracks[0]!.getCodecParameterString()).toBe('mp4a.40.2');
|
expect(await audioTracks[0]!.getCodecParameterString()).toBe('mp4a.40.2');
|
||||||
expect(audioTracks[0]!.bitrate).toBe(2149280);
|
expect(audioTracks[0]!.bitrate).toBe(2149280);
|
||||||
expect(audioTracks[0]!.name).toBe('720');
|
expect(audioTracks[0]!.name).toBe('720');
|
||||||
expect(audioTracks[0]!.groupId).toBe(2);
|
|
||||||
expect(audioTracks[0]!.pairingMask).toBe(1n << 0n);
|
|
||||||
expect(audioTracks[0]!.isHydrated).toBe(false);
|
expect(audioTracks[0]!.isHydrated).toBe(false);
|
||||||
expect(audioTracks[0]!.id).toBe(1);
|
expect(audioTracks[0]!.id).toBe(1);
|
||||||
expect(() => audioTracks[0]?.numberOfChannels).toThrow();
|
expect(() => audioTracks[0]?.numberOfChannels).toThrow();
|
||||||
@@ -101,8 +89,6 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(await audioTracks[1]!.getCodecParameterString()).toBe('mp4a.40.5');
|
expect(await audioTracks[1]!.getCodecParameterString()).toBe('mp4a.40.5');
|
||||||
expect(audioTracks[1]!.bitrate).toBe(246440);
|
expect(audioTracks[1]!.bitrate).toBe(246440);
|
||||||
expect(audioTracks[1]!.name).toBe('240');
|
expect(audioTracks[1]!.name).toBe('240');
|
||||||
expect(audioTracks[1]!.groupId).toBe(2);
|
|
||||||
expect(audioTracks[1]!.pairingMask).toBe(1n << 1n);
|
|
||||||
expect(audioTracks[1]!.isHydrated).toBe(false);
|
expect(audioTracks[1]!.isHydrated).toBe(false);
|
||||||
expect(audioTracks[1]!.id).toBe(3);
|
expect(audioTracks[1]!.id).toBe(3);
|
||||||
|
|
||||||
@@ -110,8 +96,6 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(await audioTracks[2]!.getCodecParameterString()).toBe('mp4a.40.5');
|
expect(await audioTracks[2]!.getCodecParameterString()).toBe('mp4a.40.5');
|
||||||
expect(audioTracks[2]!.bitrate).toBe(460560);
|
expect(audioTracks[2]!.bitrate).toBe(460560);
|
||||||
expect(audioTracks[2]!.name).toBe('380');
|
expect(audioTracks[2]!.name).toBe('380');
|
||||||
expect(audioTracks[2]!.groupId).toBe(2);
|
|
||||||
expect(audioTracks[2]!.pairingMask).toBe(1n << 2n);
|
|
||||||
expect(audioTracks[2]!.isHydrated).toBe(false);
|
expect(audioTracks[2]!.isHydrated).toBe(false);
|
||||||
expect(audioTracks[2]!.id).toBe(5);
|
expect(audioTracks[2]!.id).toBe(5);
|
||||||
|
|
||||||
@@ -119,8 +103,6 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(await audioTracks[3]!.getCodecParameterString()).toBe('mp4a.40.2');
|
expect(await audioTracks[3]!.getCodecParameterString()).toBe('mp4a.40.2');
|
||||||
expect(audioTracks[3]!.bitrate).toBe(836280);
|
expect(audioTracks[3]!.bitrate).toBe(836280);
|
||||||
expect(audioTracks[3]!.name).toBe('480');
|
expect(audioTracks[3]!.name).toBe('480');
|
||||||
expect(audioTracks[3]!.groupId).toBe(2);
|
|
||||||
expect(audioTracks[3]!.pairingMask).toBe(1n << 3n);
|
|
||||||
expect(audioTracks[3]!.isHydrated).toBe(false);
|
expect(audioTracks[3]!.isHydrated).toBe(false);
|
||||||
expect(audioTracks[3]!.id).toBe(7);
|
expect(audioTracks[3]!.id).toBe(7);
|
||||||
|
|
||||||
@@ -128,14 +110,20 @@ test.concurrent('Big Buck Bunny', { timeout: 15_000 }, async () => {
|
|||||||
expect(await audioTracks[4]!.getCodecParameterString()).toBe('mp4a.40.2');
|
expect(await audioTracks[4]!.getCodecParameterString()).toBe('mp4a.40.2');
|
||||||
expect(audioTracks[4]!.bitrate).toBe(6221600);
|
expect(audioTracks[4]!.bitrate).toBe(6221600);
|
||||||
expect(audioTracks[4]!.name).toBe('1080');
|
expect(audioTracks[4]!.name).toBe('1080');
|
||||||
expect(audioTracks[4]!.groupId).toBe(2);
|
|
||||||
expect(audioTracks[4]!.pairingMask).toBe(1n << 4n);
|
|
||||||
expect(audioTracks[4]!.isHydrated).toBe(false);
|
expect(audioTracks[4]!.isHydrated).toBe(false);
|
||||||
expect(audioTracks[4]!.id).toBe(9);
|
expect(audioTracks[4]!.id).toBe(9);
|
||||||
|
|
||||||
expect(videoTracks[0]!.canBePairedWith(videoTracks[1]!)).toBe(false);
|
for (let i = 0; i < videoTracks.length - 1; i++) {
|
||||||
expect(videoTracks[0]!.canBePairedWith(audioTracks[0]!)).toBe(true);
|
for (let j = i + 1; j < videoTracks.length; j++) {
|
||||||
expect(videoTracks[0]!.canBePairedWith(audioTracks[1]!)).toBe(false);
|
expect(videoTracks[i]!.canBePairedWith(videoTracks[j]!)).toBe(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < videoTracks.length; i++) {
|
||||||
|
for (let j = 0; j < audioTracks.length; j++) {
|
||||||
|
expect(videoTracks[i]!.canBePairedWith(audioTracks[j]!)).toBe(i === j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const primaryVideoTrack = await input.getPrimaryVideoTrack();
|
const primaryVideoTrack = await input.getPrimaryVideoTrack();
|
||||||
const primaryAudioTrack = await input.getPrimaryAudioTrack();
|
const primaryAudioTrack = await input.getPrimaryAudioTrack();
|
||||||
@@ -608,7 +596,7 @@ test.concurrent('Advanced Apple HLS', { timeout: 30_000 }, async () => {
|
|||||||
const audioTracks = tracks.filter(x => x.isAudioTrack());
|
const audioTracks = tracks.filter(x => x.isAudioTrack());
|
||||||
|
|
||||||
expect(audioTracks).toHaveLength(3);
|
expect(audioTracks).toHaveLength(3);
|
||||||
expect(videoTracks).toHaveLength(64);
|
expect(videoTracks).toHaveLength(28);
|
||||||
|
|
||||||
expect(audioTracks[0]).toMatchObject({ codec: 'aac', name: 'English', languageCode: 'en' });
|
expect(audioTracks[0]).toMatchObject({ codec: 'aac', name: 'English', languageCode: 'en' });
|
||||||
expect(audioTracks[1]).toMatchObject({ codec: 'ac3', name: 'English', languageCode: 'en' });
|
expect(audioTracks[1]).toMatchObject({ codec: 'ac3', name: 'English', languageCode: 'en' });
|
||||||
@@ -622,7 +610,7 @@ test.concurrent('Advanced Apple HLS', { timeout: 30_000 }, async () => {
|
|||||||
expect(await audioTracks[1]!.getPairableVideoTracks()).toHaveLength(18);
|
expect(await audioTracks[1]!.getPairableVideoTracks()).toHaveLength(18);
|
||||||
expect(await audioTracks[2]!.getPairableVideoTracks()).toHaveLength(18);
|
expect(await audioTracks[2]!.getPairableVideoTracks()).toHaveLength(18);
|
||||||
|
|
||||||
// I-FRAME AVC (5 tracks)
|
// I-FRAME AVC
|
||||||
|
|
||||||
expect(videoTracks[0]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 1015727, hasOnlyKeyPackets: true });
|
expect(videoTracks[0]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 1015727, hasOnlyKeyPackets: true });
|
||||||
expect(videoTracks[1]).toMatchObject({ codec: 'avc', displayWidth: 1280, displayHeight: 720, bitrate: 760174, hasOnlyKeyPackets: true });
|
expect(videoTracks[1]).toMatchObject({ codec: 'avc', displayWidth: 1280, displayHeight: 720, bitrate: 760174, hasOnlyKeyPackets: true });
|
||||||
@@ -636,17 +624,22 @@ test.concurrent('Advanced Apple HLS', { timeout: 30_000 }, async () => {
|
|||||||
expect(await videoTracks[3]!.getCodecParameterString()).toBe('avc1.64001f');
|
expect(await videoTracks[3]!.getCodecParameterString()).toBe('avc1.64001f');
|
||||||
expect(await videoTracks[4]!.getCodecParameterString()).toBe('avc1.64001f');
|
expect(await videoTracks[4]!.getCodecParameterString()).toBe('avc1.64001f');
|
||||||
|
|
||||||
// AVC + audio group a1 (9 tracks)
|
for (let i = 0; i <= 4; i++) {
|
||||||
|
const videoTrack = videoTracks[i]!;
|
||||||
|
expect(audioTracks.some(x => x.canBePairedWith(videoTrack))).toBe(false);
|
||||||
|
}
|
||||||
|
|
||||||
expect(videoTracks[5]).toMatchObject({ codec: 'avc', displayWidth: 960, displayHeight: 540, bitrate: 2523597, hasOnlyKeyPackets: false });
|
// AVC
|
||||||
expect(videoTracks[6]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 9873268, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[7]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 7318337, hasOnlyKeyPackets: false });
|
expect(videoTracks[5]).toMatchObject({ codec: 'avc', displayWidth: 960, displayHeight: 540, bitrate: 2746096, hasOnlyKeyPackets: false });
|
||||||
expect(videoTracks[8]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 5421720, hasOnlyKeyPackets: false });
|
expect(videoTracks[6]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 10095767, hasOnlyKeyPackets: false });
|
||||||
expect(videoTracks[9]).toMatchObject({ codec: 'avc', displayWidth: 1280, displayHeight: 720, bitrate: 3611257, hasOnlyKeyPackets: false });
|
expect(videoTracks[7]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 7540836, hasOnlyKeyPackets: false });
|
||||||
expect(videoTracks[10]).toMatchObject({ codec: 'avc', displayWidth: 768, displayHeight: 432, bitrate: 1475903, hasOnlyKeyPackets: false });
|
expect(videoTracks[8]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 5644219, hasOnlyKeyPackets: false });
|
||||||
expect(videoTracks[11]).toMatchObject({ codec: 'avc', displayWidth: 640, displayHeight: 360, bitrate: 1017705, hasOnlyKeyPackets: false });
|
expect(videoTracks[9]).toMatchObject({ codec: 'avc', displayWidth: 1280, displayHeight: 720, bitrate: 3833756, hasOnlyKeyPackets: false });
|
||||||
expect(videoTracks[12]).toMatchObject({ codec: 'avc', displayWidth: 480, displayHeight: 270, bitrate: 582820, hasOnlyKeyPackets: false });
|
expect(videoTracks[10]).toMatchObject({ codec: 'avc', displayWidth: 768, displayHeight: 432, bitrate: 1698402, hasOnlyKeyPackets: false });
|
||||||
expect(videoTracks[13]).toMatchObject({ codec: 'avc', displayWidth: 416, displayHeight: 234, bitrate: 339404, hasOnlyKeyPackets: false });
|
expect(videoTracks[11]).toMatchObject({ codec: 'avc', displayWidth: 640, displayHeight: 360, bitrate: 1240204, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[12]).toMatchObject({ codec: 'avc', displayWidth: 480, displayHeight: 270, bitrate: 805319, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[13]).toMatchObject({ codec: 'avc', displayWidth: 416, displayHeight: 234, bitrate: 561903, hasOnlyKeyPackets: false });
|
||||||
|
|
||||||
expect(await videoTracks[5]!.getCodecParameterString()).toBe('avc1.640020');
|
expect(await videoTracks[5]!.getCodecParameterString()).toBe('avc1.640020');
|
||||||
expect(await videoTracks[6]!.getCodecParameterString()).toBe('avc1.64002a');
|
expect(await videoTracks[6]!.getCodecParameterString()).toBe('avc1.64002a');
|
||||||
@@ -658,129 +651,56 @@ test.concurrent('Advanced Apple HLS', { timeout: 30_000 }, async () => {
|
|||||||
expect(await videoTracks[12]!.getCodecParameterString()).toBe('avc1.64001f');
|
expect(await videoTracks[12]!.getCodecParameterString()).toBe('avc1.64001f');
|
||||||
expect(await videoTracks[13]!.getCodecParameterString()).toBe('avc1.64001f');
|
expect(await videoTracks[13]!.getCodecParameterString()).toBe('avc1.64001f');
|
||||||
|
|
||||||
// AVC + audio group a2 (9 tracks)
|
for (let i = 5; i <= 13; i++) {
|
||||||
|
const videoTrack = videoTracks[i]!;
|
||||||
|
expect(audioTracks.every(x => x.canBePairedWith(videoTrack))).toBe(true);
|
||||||
|
}
|
||||||
|
|
||||||
expect(videoTracks[14]).toMatchObject({ codec: 'avc', displayWidth: 960, displayHeight: 540, bitrate: 2746096, hasOnlyKeyPackets: false });
|
// I-FRAME HEVC
|
||||||
expect(videoTracks[15]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 10095767, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[16]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 7540836, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[17]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 5644219, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[18]).toMatchObject({ codec: 'avc', displayWidth: 1280, displayHeight: 720, bitrate: 3833756, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[19]).toMatchObject({ codec: 'avc', displayWidth: 768, displayHeight: 432, bitrate: 1698402, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[20]).toMatchObject({ codec: 'avc', displayWidth: 640, displayHeight: 360, bitrate: 1240204, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[21]).toMatchObject({ codec: 'avc', displayWidth: 480, displayHeight: 270, bitrate: 805319, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[22]).toMatchObject({ codec: 'avc', displayWidth: 416, displayHeight: 234, bitrate: 561903, hasOnlyKeyPackets: false });
|
|
||||||
|
|
||||||
expect(await videoTracks[14]!.getCodecParameterString()).toBe('avc1.640020');
|
expect(videoTracks[14]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 328352, hasOnlyKeyPackets: true });
|
||||||
expect(await videoTracks[15]!.getCodecParameterString()).toBe('avc1.64002a');
|
expect(videoTracks[15]).toMatchObject({ codec: 'hevc', displayWidth: 1280, displayHeight: 720, bitrate: 226274, hasOnlyKeyPackets: true });
|
||||||
expect(await videoTracks[16]!.getCodecParameterString()).toBe('avc1.64002a');
|
expect(videoTracks[16]).toMatchObject({ codec: 'hevc', displayWidth: 960, displayHeight: 540, bitrate: 159037, hasOnlyKeyPackets: true });
|
||||||
expect(await videoTracks[17]!.getCodecParameterString()).toBe('avc1.64002a');
|
expect(videoTracks[17]).toMatchObject({ codec: 'hevc', displayWidth: 640, displayHeight: 360, bitrate: 92800, hasOnlyKeyPackets: true });
|
||||||
expect(await videoTracks[18]!.getCodecParameterString()).toBe('avc1.640020');
|
expect(videoTracks[18]).toMatchObject({ codec: 'hevc', displayWidth: 480, displayHeight: 270, bitrate: 51760, hasOnlyKeyPackets: true });
|
||||||
expect(await videoTracks[19]!.getCodecParameterString()).toBe('avc1.64001f');
|
|
||||||
expect(await videoTracks[20]!.getCodecParameterString()).toBe('avc1.64001f');
|
|
||||||
expect(await videoTracks[21]!.getCodecParameterString()).toBe('avc1.64001f');
|
|
||||||
expect(await videoTracks[22]!.getCodecParameterString()).toBe('avc1.64001f');
|
|
||||||
|
|
||||||
// AVC + audio group a3 (9 tracks)
|
expect(await videoTracks[14]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
expect(await videoTracks[15]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
expect(await videoTracks[16]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
expect(await videoTracks[17]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
expect(await videoTracks[18]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
|
||||||
expect(videoTracks[23]).toMatchObject({ codec: 'avc', displayWidth: 960, displayHeight: 540, bitrate: 2554096, hasOnlyKeyPackets: false });
|
for (let i = 14; i <= 18; i++) {
|
||||||
expect(videoTracks[24]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 9903767, hasOnlyKeyPackets: false });
|
const videoTrack = videoTracks[i]!;
|
||||||
expect(videoTracks[25]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 7348836, hasOnlyKeyPackets: false });
|
expect(audioTracks.some(x => x.canBePairedWith(videoTrack))).toBe(false);
|
||||||
expect(videoTracks[26]).toMatchObject({ codec: 'avc', displayWidth: 1920, displayHeight: 1080, bitrate: 5452219, hasOnlyKeyPackets: false });
|
}
|
||||||
expect(videoTracks[27]).toMatchObject({ codec: 'avc', displayWidth: 1280, displayHeight: 720, bitrate: 3641756, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[28]).toMatchObject({ codec: 'avc', displayWidth: 768, displayHeight: 432, bitrate: 1506402, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[29]).toMatchObject({ codec: 'avc', displayWidth: 640, displayHeight: 360, bitrate: 1048204, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[30]).toMatchObject({ codec: 'avc', displayWidth: 480, displayHeight: 270, bitrate: 613319, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[31]).toMatchObject({ codec: 'avc', displayWidth: 416, displayHeight: 234, bitrate: 369903, hasOnlyKeyPackets: false });
|
|
||||||
|
|
||||||
expect(await videoTracks[23]!.getCodecParameterString()).toBe('avc1.640020');
|
// HEVC
|
||||||
expect(await videoTracks[24]!.getCodecParameterString()).toBe('avc1.64002a');
|
|
||||||
expect(await videoTracks[25]!.getCodecParameterString()).toBe('avc1.64002a');
|
|
||||||
expect(await videoTracks[26]!.getCodecParameterString()).toBe('avc1.64002a');
|
|
||||||
expect(await videoTracks[27]!.getCodecParameterString()).toBe('avc1.640020');
|
|
||||||
expect(await videoTracks[28]!.getCodecParameterString()).toBe('avc1.64001f');
|
|
||||||
expect(await videoTracks[29]!.getCodecParameterString()).toBe('avc1.64001f');
|
|
||||||
expect(await videoTracks[30]!.getCodecParameterString()).toBe('avc1.64001f');
|
|
||||||
expect(await videoTracks[31]!.getCodecParameterString()).toBe('avc1.64001f');
|
|
||||||
|
|
||||||
// I-FRAME HEVC (5 tracks)
|
expect(videoTracks[19]).toMatchObject({ codec: 'hevc', displayWidth: 960, displayHeight: 540, bitrate: 2386827, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[20]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 6886727, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[21]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 5650398, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[22]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 4302269, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[23]).toMatchObject({ codec: 'hevc', displayWidth: 1280, displayHeight: 720, bitrate: 2987200, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[24]).toMatchObject({ codec: 'hevc', displayWidth: 768, displayHeight: 432, bitrate: 1448754, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[25]).toMatchObject({ codec: 'hevc', displayWidth: 640, displayHeight: 360, bitrate: 1124269, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[26]).toMatchObject({ codec: 'hevc', displayWidth: 480, displayHeight: 270, bitrate: 771426, hasOnlyKeyPackets: false });
|
||||||
|
expect(videoTracks[27]).toMatchObject({ codec: 'hevc', displayWidth: 416, displayHeight: 234, bitrate: 563212, hasOnlyKeyPackets: false });
|
||||||
|
|
||||||
expect(videoTracks[32]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 328352, hasOnlyKeyPackets: true });
|
expect(await videoTracks[19]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
expect(videoTracks[33]).toMatchObject({ codec: 'hevc', displayWidth: 1280, displayHeight: 720, bitrate: 226274, hasOnlyKeyPackets: true });
|
expect(await videoTracks[20]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
expect(videoTracks[34]).toMatchObject({ codec: 'hevc', displayWidth: 960, displayHeight: 540, bitrate: 159037, hasOnlyKeyPackets: true });
|
expect(await videoTracks[21]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
expect(videoTracks[35]).toMatchObject({ codec: 'hevc', displayWidth: 640, displayHeight: 360, bitrate: 92800, hasOnlyKeyPackets: true });
|
expect(await videoTracks[22]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
expect(videoTracks[36]).toMatchObject({ codec: 'hevc', displayWidth: 480, displayHeight: 270, bitrate: 51760, hasOnlyKeyPackets: true });
|
expect(await videoTracks[23]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
expect(await videoTracks[24]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
expect(await videoTracks[25]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
expect(await videoTracks[26]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
expect(await videoTracks[27]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
||||||
|
|
||||||
expect(await videoTracks[32]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
for (let i = 19; i <= 27; i++) {
|
||||||
expect(await videoTracks[33]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
const videoTrack = videoTracks[i]!;
|
||||||
expect(await videoTracks[34]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
expect(audioTracks.every(x => x.canBePairedWith(videoTrack))).toBe(true);
|
||||||
expect(await videoTracks[35]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
}
|
||||||
expect(await videoTracks[36]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
|
|
||||||
// HEVC + audio group a1 (9 tracks)
|
|
||||||
|
|
||||||
expect(videoTracks[37]).toMatchObject({ codec: 'hevc', displayWidth: 960, displayHeight: 540, bitrate: 2164328, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[38]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 6664228, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[39]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 5427899, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[40]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 4079770, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[41]).toMatchObject({ codec: 'hevc', displayWidth: 1280, displayHeight: 720, bitrate: 2764701, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[42]).toMatchObject({ codec: 'hevc', displayWidth: 768, displayHeight: 432, bitrate: 1226255, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[43]).toMatchObject({ codec: 'hevc', displayWidth: 640, displayHeight: 360, bitrate: 901770, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[44]).toMatchObject({ codec: 'hevc', displayWidth: 480, displayHeight: 270, bitrate: 548927, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[45]).toMatchObject({ codec: 'hevc', displayWidth: 416, displayHeight: 234, bitrate: 340713, hasOnlyKeyPackets: false });
|
|
||||||
|
|
||||||
expect(await videoTracks[37]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[38]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[39]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[40]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[41]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[42]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[43]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[44]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[45]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
|
|
||||||
// HEVC + audio group a2 (9 tracks)
|
|
||||||
|
|
||||||
expect(videoTracks[46]).toMatchObject({ codec: 'hevc', displayWidth: 960, displayHeight: 540, bitrate: 2386827, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[47]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 6886727, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[48]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 5650398, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[49]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 4302269, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[50]).toMatchObject({ codec: 'hevc', displayWidth: 1280, displayHeight: 720, bitrate: 2987200, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[51]).toMatchObject({ codec: 'hevc', displayWidth: 768, displayHeight: 432, bitrate: 1448754, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[52]).toMatchObject({ codec: 'hevc', displayWidth: 640, displayHeight: 360, bitrate: 1124269, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[53]).toMatchObject({ codec: 'hevc', displayWidth: 480, displayHeight: 270, bitrate: 771426, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[54]).toMatchObject({ codec: 'hevc', displayWidth: 416, displayHeight: 234, bitrate: 563212, hasOnlyKeyPackets: false });
|
|
||||||
|
|
||||||
expect(await videoTracks[46]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[47]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[48]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[49]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[50]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[51]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[52]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[53]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[54]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
|
|
||||||
// HEVC + audio group a3 (9 tracks)
|
|
||||||
|
|
||||||
expect(videoTracks[55]).toMatchObject({ codec: 'hevc', displayWidth: 960, displayHeight: 540, bitrate: 2194827, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[56]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 6694727, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[57]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 5458398, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[58]).toMatchObject({ codec: 'hevc', displayWidth: 1920, displayHeight: 1080, bitrate: 4110269, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[59]).toMatchObject({ codec: 'hevc', displayWidth: 1280, displayHeight: 720, bitrate: 2795200, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[60]).toMatchObject({ codec: 'hevc', displayWidth: 768, displayHeight: 432, bitrate: 1256754, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[61]).toMatchObject({ codec: 'hevc', displayWidth: 640, displayHeight: 360, bitrate: 932269, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[62]).toMatchObject({ codec: 'hevc', displayWidth: 480, displayHeight: 270, bitrate: 579426, hasOnlyKeyPackets: false });
|
|
||||||
expect(videoTracks[63]).toMatchObject({ codec: 'hevc', displayWidth: 416, displayHeight: 234, bitrate: 371212, hasOnlyKeyPackets: false });
|
|
||||||
|
|
||||||
expect(await videoTracks[55]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[56]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[57]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[58]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[59]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[60]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[61]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[62]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
expect(await videoTracks[63]!.getCodecParameterString()).toBe('hvc1.2.4.L123.B0');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test.concurrent('Live HLS', { timeout: 30_000 }, async () => {
|
test.concurrent('Live HLS', { timeout: 30_000 }, async () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user