mirror of
https://github.com/arcodange-org/mediabunny.git
synced 2026-10-01 04:43:51 +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;
|
||||
}
|
||||
|
||||
getGroupId() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
getPairingMask() {
|
||||
return 1n;
|
||||
}
|
||||
|
||||
@@ -602,10 +602,6 @@ class FlacAudioTrackBacking implements InputAudioTrackBacking {
|
||||
return false;
|
||||
}
|
||||
|
||||
getGroupId() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
getPairingMask() {
|
||||
return 1n;
|
||||
}
|
||||
|
||||
+27
-22
@@ -30,7 +30,6 @@ type InternalTrack = {
|
||||
|
||||
fullPath: string;
|
||||
fullCodecString: string;
|
||||
groupId: number;
|
||||
pairingMask: bigint;
|
||||
peakBitrate: 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.
|
||||
|
||||
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');
|
||||
let codecStrings: string[];
|
||||
@@ -334,7 +333,7 @@ export class HlsDemuxer extends Demuxer {
|
||||
}
|
||||
}
|
||||
|
||||
result.push({ track: {
|
||||
result.push({
|
||||
id: -1,
|
||||
demuxer: this,
|
||||
inputTrack: null,
|
||||
@@ -345,7 +344,6 @@ export class HlsDemuxer extends Demuxer {
|
||||
lineNumber: variantStream.lineNumber,
|
||||
fullPath: variantStream.fullPath,
|
||||
fullCodecString: videoCodecString,
|
||||
groupId: 1,
|
||||
pairingMask: 1n << BigInt(i),
|
||||
peakBitrate: bandwidth,
|
||||
averageBitrate: averageBandwidth,
|
||||
@@ -356,7 +354,7 @@ export class HlsDemuxer extends Demuxer {
|
||||
width,
|
||||
height,
|
||||
},
|
||||
}, canMerge: false });
|
||||
});
|
||||
} else {
|
||||
if (!videoGroupIds.includes(videoGroupId)) {
|
||||
throw new Error(
|
||||
@@ -386,7 +384,7 @@ export class HlsDemuxer extends Demuxer {
|
||||
}
|
||||
}
|
||||
|
||||
result.push({ track: {
|
||||
result.push({
|
||||
id: -1,
|
||||
demuxer: this,
|
||||
inputTrack: null,
|
||||
@@ -399,7 +397,6 @@ export class HlsDemuxer extends Demuxer {
|
||||
lineNumber: mediaTag.lineNumber,
|
||||
fullPath: mediaTag.fullPath ?? variantStream.fullPath,
|
||||
fullCodecString: videoCodecString,
|
||||
groupId: 3 + videoGroupIds.indexOf(groupId),
|
||||
pairingMask: 1n << BigInt(i),
|
||||
peakBitrate: null,
|
||||
averageBitrate: null,
|
||||
@@ -410,7 +407,7 @@ export class HlsDemuxer extends Demuxer {
|
||||
width,
|
||||
height,
|
||||
},
|
||||
}, canMerge: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
} else if (AUDIO_CODECS.includes(inferredCodec as AudioCodec)) {
|
||||
@@ -431,7 +428,7 @@ export class HlsDemuxer extends Demuxer {
|
||||
? Number(channels)
|
||||
: null;
|
||||
|
||||
result.push({ track: {
|
||||
result.push({
|
||||
id: -1,
|
||||
demuxer: this,
|
||||
inputTrack: null,
|
||||
@@ -442,7 +439,6 @@ export class HlsDemuxer extends Demuxer {
|
||||
lineNumber: variantStream.lineNumber,
|
||||
fullPath: variantStream.fullPath,
|
||||
fullCodecString: audioCodecString,
|
||||
groupId: 2,
|
||||
pairingMask: 1n << BigInt(i),
|
||||
peakBitrate: bandwidth,
|
||||
averageBitrate: averageBandwidth,
|
||||
@@ -457,7 +453,7 @@ export class HlsDemuxer extends Demuxer {
|
||||
? parsedChannels
|
||||
: null,
|
||||
},
|
||||
}, canMerge: false });
|
||||
});
|
||||
} else {
|
||||
if (!audioGroupIds.includes(audioGroupId)) {
|
||||
throw new Error(
|
||||
@@ -480,7 +476,7 @@ export class HlsDemuxer extends Demuxer {
|
||||
? Number(channels)
|
||||
: null;
|
||||
|
||||
result.push({ track: {
|
||||
result.push({
|
||||
id: -1,
|
||||
demuxer: this,
|
||||
inputTrack: null,
|
||||
@@ -493,7 +489,6 @@ export class HlsDemuxer extends Demuxer {
|
||||
lineNumber: mediaTag.lineNumber,
|
||||
fullPath: mediaTag.fullPath ?? variantStream.fullPath,
|
||||
fullCodecString: audioCodecString,
|
||||
groupId: 3 + videoGroupIds.length + audioGroupIds.indexOf(groupId),
|
||||
pairingMask: 1n << BigInt(i),
|
||||
peakBitrate: null,
|
||||
averageBitrate: null,
|
||||
@@ -508,7 +503,7 @@ export class HlsDemuxer extends Demuxer {
|
||||
? parsedChannels
|
||||
: null,
|
||||
},
|
||||
}, canMerge: true });
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -518,16 +513,30 @@ export class HlsDemuxer extends Demuxer {
|
||||
}));
|
||||
|
||||
const internalTracks: InternalTrack[] = [];
|
||||
const addInternalTrack = (track: InternalTrack, canMerge: boolean) => {
|
||||
const addInternalTrack = (track: InternalTrack) => {
|
||||
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.default ||= track.default;
|
||||
existingTrack.autoselect ||= track.autoselect;
|
||||
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) {
|
||||
existingTrack.languageCode = track.languageCode;
|
||||
}
|
||||
@@ -539,7 +548,7 @@ export class HlsDemuxer extends Demuxer {
|
||||
|
||||
for (const variantInternalTracks of internalTracksByVariant) {
|
||||
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;
|
||||
}
|
||||
|
||||
getGroupId(): number {
|
||||
return this.internalTrack.groupId;
|
||||
}
|
||||
|
||||
getPairingMask(): bigint {
|
||||
return this.internalTrack.pairingMask;
|
||||
}
|
||||
|
||||
+11
-27
@@ -2,7 +2,15 @@ import { MediaCodec, validateAudioChunkMetadata, validateVideoChunkMetadata } fr
|
||||
import { EncodedAudioPacketSource, EncodedVideoPacketSource, MediaSource } from '../media-source';
|
||||
import { assert, joinPaths, textEncoder, UNDETERMINED_LANGUAGE } from '../misc';
|
||||
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 { EncodedPacket } from '../packet';
|
||||
import { SubtitleCue, SubtitleMetadata } from '../subtitles';
|
||||
@@ -101,38 +109,13 @@ export class HlsMuxer extends Muxer {
|
||||
}
|
||||
|
||||
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) {
|
||||
if (track === otherTrack) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let pairable = false;
|
||||
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) {
|
||||
if (!outputTracksArePairable(track, otherTrack)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -828,6 +811,7 @@ export class HlsMuxer extends Muxer {
|
||||
}
|
||||
}
|
||||
|
||||
// Write all playlists in parallel
|
||||
const playlistPromises = this.playlists.map(async (playlist) => {
|
||||
let targetDuration = this.targetSegmentDuration;
|
||||
for (const segment of playlist.writtenSegments) {
|
||||
|
||||
+5
-12
@@ -41,7 +41,6 @@ export interface InputTrackBacking {
|
||||
getTimeResolution(): number;
|
||||
getTimestampsAreRelativeToUnixEpoch(): boolean;
|
||||
getDisposition(): TrackDisposition;
|
||||
getGroupId(): number;
|
||||
getPairingMask(): bigint;
|
||||
getBitrate(): number | null;
|
||||
getAverageBitrate(): number | null;
|
||||
@@ -118,14 +117,6 @@ export abstract class InputTrack {
|
||||
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
|
||||
* and depends entirely on the container format.
|
||||
@@ -310,9 +301,11 @@ export abstract class InputTrack {
|
||||
return true;
|
||||
}
|
||||
|
||||
return this.input === otherTrack.input
|
||||
&& this.groupId !== otherTrack.groupId // This also prevents the track from being paired with itself
|
||||
&& (this.pairingMask & otherTrack.pairingMask) !== 0n;
|
||||
if (this.input !== otherTrack.input || this === otherTrack) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (this._backing.getPairingMask() & otherTrack._backing.getPairingMask()) !== 0n;
|
||||
}
|
||||
|
||||
async getPairableTracks(query?: TrackQuery<InputTrack>) {
|
||||
|
||||
@@ -39,6 +39,7 @@ import {
|
||||
InputAudioTrackBacking,
|
||||
InputTrack,
|
||||
InputTrackBacking,
|
||||
|
||||
InputVideoTrack,
|
||||
InputVideoTrackBacking,
|
||||
} from '../input-track';
|
||||
@@ -2565,10 +2566,6 @@ abstract class IsobmffTrackBacking implements InputTrackBacking {
|
||||
return this.internalTrack.disposition;
|
||||
}
|
||||
|
||||
getGroupId() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
getPairingMask() {
|
||||
return 1n;
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
InputAudioTrackBacking,
|
||||
InputTrack,
|
||||
InputTrackBacking,
|
||||
|
||||
InputVideoTrack,
|
||||
InputVideoTrackBacking,
|
||||
} from '../input-track';
|
||||
@@ -1978,10 +1979,6 @@ abstract class MatroskaTrackBacking implements InputTrackBacking {
|
||||
return this.internalTrack.disposition;
|
||||
}
|
||||
|
||||
getGroupId() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
getPairingMask() {
|
||||
return 1n;
|
||||
}
|
||||
|
||||
@@ -293,10 +293,6 @@ class Mp3AudioTrackBacking implements InputAudioTrackBacking {
|
||||
return false;
|
||||
}
|
||||
|
||||
getGroupId() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
getPairingMask() {
|
||||
return 1n;
|
||||
}
|
||||
|
||||
@@ -45,6 +45,7 @@ import {
|
||||
InputAudioTrackBacking,
|
||||
InputTrack,
|
||||
InputTrackBacking,
|
||||
|
||||
InputVideoTrack,
|
||||
InputVideoTrackBacking,
|
||||
} from '../input-track';
|
||||
@@ -1099,10 +1100,6 @@ abstract class MpegTsTrackBacking implements InputTrackBacking {
|
||||
return false;
|
||||
}
|
||||
|
||||
getGroupId() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
getPairingMask() {
|
||||
return 1n;
|
||||
}
|
||||
|
||||
@@ -452,10 +452,6 @@ class OggAudioTrackBacking implements InputAudioTrackBacking {
|
||||
return false;
|
||||
}
|
||||
|
||||
getGroupId() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
getPairingMask() {
|
||||
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.
|
||||
* @group Output files
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
InputAudioTrackBacking,
|
||||
InputTrack,
|
||||
InputTrackBacking,
|
||||
|
||||
InputVideoTrack,
|
||||
InputVideoTrackBacking,
|
||||
} from './input-track';
|
||||
@@ -222,11 +223,7 @@ class SegmentedInputInputTrackBacking implements InputTrackBacking {
|
||||
return this.firstInputTrack._backing.getId();
|
||||
}
|
||||
|
||||
getGroupId(): number {
|
||||
return this.firstInputTrack._backing.getGroupId();
|
||||
}
|
||||
|
||||
getPairingMask(): bigint {
|
||||
getPairingMask() {
|
||||
return this.firstInputTrack._backing.getPairingMask();
|
||||
}
|
||||
|
||||
|
||||
@@ -405,10 +405,6 @@ class WaveAudioTrackBacking implements InputAudioTrackBacking {
|
||||
return false;
|
||||
}
|
||||
|
||||
getGroupId() {
|
||||
return this.getId();
|
||||
}
|
||||
|
||||
getPairingMask() {
|
||||
return 1n;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user