85 lines
2.1 KiB
TypeScript
85 lines
2.1 KiB
TypeScript
import {type EbmlCuePointTagType, type EbmlCuesTagType, EbmlTagIdEnum} from "konoebml";
|
|
import {CuePointSchema, type CuePointType, type CueTrackPositionsType} from "../schema";
|
|
import {maxBy} from "lodash-es";
|
|
import type {SegmentComponent} from "./segment";
|
|
import {SegmentComponentSystemTrait} from "./segment-component";
|
|
|
|
export class CueSystem extends SegmentComponentSystemTrait<
|
|
EbmlCuePointTagType,
|
|
typeof CuePointSchema
|
|
> {
|
|
override get schema() {
|
|
return CuePointSchema;
|
|
}
|
|
|
|
cues: SegmentComponent<CuePointType>[] = [];
|
|
|
|
prepareCuesWithTag(tag: EbmlCuesTagType) {
|
|
this.cues = tag.children
|
|
.filter((c) => c.id === EbmlTagIdEnum.CuePoint)
|
|
.map(this.componentFromTag.bind(this));
|
|
return this;
|
|
}
|
|
|
|
findClosestCue(seekTime: number): CuePointType | undefined {
|
|
const cues = this.cues;
|
|
if (!cues || cues.length === 0) {
|
|
return undefined;
|
|
}
|
|
|
|
let left = 0;
|
|
let right = cues.length - 1;
|
|
|
|
if (seekTime <= cues[0].CueTime) {
|
|
return cues[0];
|
|
}
|
|
|
|
if (seekTime >= cues[right].CueTime) {
|
|
return cues[right];
|
|
}
|
|
|
|
while (left <= right) {
|
|
const mid = Math.floor((left + right) / 2);
|
|
|
|
if (cues[mid].CueTime === seekTime) {
|
|
return cues[mid];
|
|
}
|
|
|
|
if (cues[mid].CueTime < seekTime) {
|
|
left = mid + 1;
|
|
} else {
|
|
right = mid - 1;
|
|
}
|
|
}
|
|
|
|
const before = cues[right];
|
|
const after = cues[left];
|
|
return Math.abs((before.CueTime as number) - seekTime) <
|
|
Math.abs((after.CueTime as number) - seekTime)
|
|
? before
|
|
: after;
|
|
}
|
|
|
|
getCueTrackPositions(
|
|
cuePoint: CuePointType,
|
|
track?: number
|
|
): CueTrackPositionsType {
|
|
let cueTrackPositions: CueTrackPositionsType | undefined;
|
|
if (track! >= 0) {
|
|
cueTrackPositions = cuePoint.CueTrackPositions.find(
|
|
(c) => c.CueTrack === track
|
|
);
|
|
}
|
|
if (!cueTrackPositions) {
|
|
cueTrackPositions = maxBy(
|
|
cuePoint.CueTrackPositions,
|
|
(c) => c.CueClusterPosition
|
|
)!;
|
|
}
|
|
return cueTrackPositions;
|
|
}
|
|
|
|
get prepared(): boolean {
|
|
return this.cues.length > 0;
|
|
}
|
|
} |