feat: add codegen and refactor mkv models
This commit is contained in:
parent
f921819d2a
commit
0b681d4fd1
@ -1,135 +1,229 @@
|
|||||||
import {
|
import {
|
||||||
type EbmlTagType,
|
type EbmlClusterTagType,
|
||||||
EbmlTagIdEnum,
|
type EbmlCuePointTagType,
|
||||||
EbmlTagPosition,
|
|
||||||
type EbmlTracksTagType,
|
|
||||||
type EbmlInfoTagType,
|
|
||||||
type EbmlCuesTagType,
|
type EbmlCuesTagType,
|
||||||
|
type EbmlInfoTagType,
|
||||||
|
type EbmlMasterTagType,
|
||||||
type EbmlSeekHeadTagType,
|
type EbmlSeekHeadTagType,
|
||||||
type EbmlSegmentTagType,
|
type EbmlSegmentTagType,
|
||||||
type EbmlCuePointTagType,
|
EbmlTagIdEnum,
|
||||||
type EbmlMasterTagType,
|
EbmlTagPosition,
|
||||||
|
type EbmlTagType,
|
||||||
|
type EbmlTrackEntryTagType,
|
||||||
|
type EbmlTracksTagType,
|
||||||
} from 'konoebml';
|
} from 'konoebml';
|
||||||
|
import {convertEbmlTagToComponent, type InferType,} from './util';
|
||||||
|
import {isEqual, maxBy} from 'lodash-es';
|
||||||
|
import {ArkErrors, type Type} from 'arktype';
|
||||||
import {
|
import {
|
||||||
convertEbmlTagToModelShape,
|
ClusterSchema,
|
||||||
type InferType,
|
type ClusterType,
|
||||||
isTagIdPos,
|
CuePointSchema,
|
||||||
SEEK_ID_KAX_CUES,
|
type CuePointType,
|
||||||
SEEK_ID_KAX_INFO,
|
type CueTrackPositionsType,
|
||||||
SEEK_ID_KAX_TRACKS,
|
InfoSchema,
|
||||||
} from './util';
|
type InfoType,
|
||||||
import { isEqual } from 'lodash-es';
|
SeekHeadSchema,
|
||||||
import type { Type } from 'arktype';
|
type SeekHeadType,
|
||||||
import { CuePointSchema, type CuePointType } from './schema';
|
TrackEntrySchema,
|
||||||
|
type TrackEntryType
|
||||||
|
} from './schema';
|
||||||
|
|
||||||
export abstract class StandardComponentSystem<
|
export const SEEK_ID_KAX_INFO = new Uint8Array([0x15, 0x49, 0xa9, 0x66]);
|
||||||
E extends EbmlMasterTagType,
|
export const SEEK_ID_KAX_TRACKS = new Uint8Array([0x16, 0x54, 0xae, 0x6b]);
|
||||||
S extends Type<any>,
|
export const SEEK_ID_KAX_CUES = new Uint8Array([0x1c, 0x53, 0xbb, 0x6b]);
|
||||||
> {
|
|
||||||
abstract get schema(): S;
|
|
||||||
|
|
||||||
componentFromTag(tag: E): InferType<S> {
|
export class SegmentSystem {
|
||||||
const extracted = convertEbmlTagToModelShape(tag);
|
startTag: EbmlSegmentTagType;
|
||||||
return this.schema.assert(extracted) as InferType<S>;
|
headTags: EbmlTagType[] = [];
|
||||||
}
|
|
||||||
}
|
cue: CueSystem;
|
||||||
|
cluster: ClusterSystem;
|
||||||
|
seek: SeekSystem;
|
||||||
|
info: InfoSystem;
|
||||||
|
track: TrackSystem;
|
||||||
|
|
||||||
export class EbmlSegment {
|
|
||||||
startNode: EbmlSegmentTagType;
|
|
||||||
seekHeadNode?: EbmlSeekHeadTagType;
|
|
||||||
seekEntries: EbmlSeekEntry[];
|
|
||||||
tracksNode?: EbmlTracksTagType;
|
|
||||||
infoNode?: EbmlInfoTagType;
|
|
||||||
cuesNode?: EbmlCuesTagType;
|
|
||||||
metaBuffer: EbmlTagType[] = [];
|
|
||||||
metaOffsets: Map<number, EbmlTagType> = new Map();
|
|
||||||
|
|
||||||
constructor(startNode: EbmlSegmentTagType) {
|
constructor(startNode: EbmlSegmentTagType) {
|
||||||
this.startNode = startNode;
|
this.startTag = startNode;
|
||||||
this.seekEntries = [];
|
this.cue = new CueSystem(this);
|
||||||
this.metaBuffer = [];
|
this.cluster = new ClusterSystem(this);
|
||||||
|
this.seek = new SeekSystem(this);
|
||||||
|
this.info = new InfoSystem(this);
|
||||||
|
this.track = new TrackSystem(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
get dataOffset() {
|
get dataStartOffset() {
|
||||||
return this.startNode.startOffset + this.startNode.headerLength;
|
return this.startTag.startOffset + this.startTag.headerLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
private addSeekHead(node: EbmlSeekHeadTagType) {
|
get startOffset () {
|
||||||
this.seekHeadNode = node;
|
return this.startTag.startOffset;
|
||||||
this.seekEntries = this.seekHeadNode.children
|
|
||||||
.filter(isTagIdPos(EbmlTagIdEnum.Seek, EbmlTagPosition.End))
|
|
||||||
.map((c) => {
|
|
||||||
const seekId = c.children.find(
|
|
||||||
(item) => item.id === EbmlTagIdEnum.SeekID
|
|
||||||
)?.data;
|
|
||||||
const seekPosition = c.children.find(
|
|
||||||
(item) => item.id === EbmlTagIdEnum.SeekPosition
|
|
||||||
)?.data as number;
|
|
||||||
if (seekId && seekPosition) {
|
|
||||||
return {
|
|
||||||
seekId,
|
|
||||||
seekPosition,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
})
|
|
||||||
.filter((c): c is EbmlSeekEntry => !!c);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findSeekPositionBySeekId(seekId: Uint8Array): number | undefined {
|
completeHeads () {
|
||||||
return this.seekEntries.find((c) => isEqual(c.seekId, seekId))
|
const infoTag = this.seek.seekTagBySeekId(SEEK_ID_KAX_INFO);
|
||||||
?.seekPosition;
|
const tracksTag = this.seek.seekTagBySeekId(SEEK_ID_KAX_TRACKS);
|
||||||
|
const cuesTag = this.seek.seekTagBySeekId(SEEK_ID_KAX_CUES);
|
||||||
|
|
||||||
|
if (cuesTag?.id === EbmlTagIdEnum.Cues) {
|
||||||
|
this.cue.prepareCuesWithTag(cuesTag)
|
||||||
|
}
|
||||||
|
if (infoTag?.id === EbmlTagIdEnum.Info) {
|
||||||
|
this.info.prepareWithInfoTag(infoTag);
|
||||||
|
}
|
||||||
|
if (tracksTag?.id === EbmlTagIdEnum.Tracks) {
|
||||||
|
this.track.prepareTracksWithTag(tracksTag);
|
||||||
}
|
}
|
||||||
|
|
||||||
findLocalNodeBySeekId(seekId: Uint8Array): EbmlTagType | undefined {
|
return this;
|
||||||
return this.findLocalNodeBySeekPosition(
|
|
||||||
this.findSeekPositionBySeekId(seekId)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
findLocalNodeBySeekPosition(
|
scanHead (tag: EbmlTagType) {
|
||||||
seekPosition: number | undefined
|
if (
|
||||||
|
tag.id === EbmlTagIdEnum.SeekHead &&
|
||||||
|
tag.position === EbmlTagPosition.End
|
||||||
|
) {
|
||||||
|
this.seek.addSeekHeadTag(tag);
|
||||||
|
}
|
||||||
|
this.headTags.push(tag);
|
||||||
|
this.seek.memoTag(tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SegmentComponentSystemTrait<E extends EbmlMasterTagType, S extends Type<any>> {
|
||||||
|
segment: SegmentSystem;
|
||||||
|
|
||||||
|
get schema(): S {
|
||||||
|
throw new Error("unimplemented!")
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(segment: SegmentSystem) {
|
||||||
|
this.segment = segment;
|
||||||
|
}
|
||||||
|
|
||||||
|
componentFromTag(tag: E): InferType<S> {
|
||||||
|
const extracted = convertEbmlTagToComponent(tag);
|
||||||
|
const result = this.schema(extracted);
|
||||||
|
if (result instanceof ArkErrors) {
|
||||||
|
const errors = result;
|
||||||
|
console.error('Parse component from tag error:', tag.toDebugRecord(), errors.flatProblemsByPath)
|
||||||
|
throw errors;
|
||||||
|
}
|
||||||
|
return result as InferType<S>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class SeekSystem extends SegmentComponentSystemTrait<EbmlSeekHeadTagType, typeof SeekHeadSchema> {
|
||||||
|
override get schema() {
|
||||||
|
return SeekHeadSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
seekHeads: SeekHeadType[] = [];
|
||||||
|
offsetToTagMemo: Map<number, EbmlTagType> = new Map();
|
||||||
|
|
||||||
|
memoTag (tag: EbmlTagType) {
|
||||||
|
this.offsetToTagMemo.set(tag.startOffset, tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
addSeekHeadTag (tag: EbmlSeekHeadTagType) {
|
||||||
|
const seekHead = this.componentFromTag(tag);
|
||||||
|
this.seekHeads.push(seekHead);
|
||||||
|
return seekHead;
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetFromSeekPosition (position: number): number {
|
||||||
|
return position + this.segment.startOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
offsetFromSeekDataPosition (position: number) : number {
|
||||||
|
return position + this.segment.dataStartOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
seekTagByStartOffset (
|
||||||
|
startOffset: number | undefined
|
||||||
): EbmlTagType | undefined {
|
): EbmlTagType | undefined {
|
||||||
return seekPosition! >= 0
|
return startOffset! >= 0
|
||||||
? this.metaOffsets.get(seekPosition as number)
|
? this.offsetToTagMemo.get(startOffset!)
|
||||||
: undefined;
|
: undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
markMetaEnd() {
|
seekOffsetBySeekId(seekId: Uint8Array): number | undefined {
|
||||||
this.infoNode = this.findLocalNodeBySeekId(
|
const seekPosition = this.seekHeads[0]?.Seek?.find((c) => isEqual(c.SeekID, seekId))
|
||||||
SEEK_ID_KAX_INFO
|
?.SeekPosition;
|
||||||
) as EbmlInfoTagType;
|
return seekPosition! >= 0 ? this.offsetFromSeekPosition(seekPosition!) : undefined;
|
||||||
this.tracksNode = this.findLocalNodeBySeekId(
|
|
||||||
SEEK_ID_KAX_TRACKS
|
|
||||||
) as EbmlTracksTagType;
|
|
||||||
this.cuesNode = this.findLocalNodeBySeekId(
|
|
||||||
SEEK_ID_KAX_CUES
|
|
||||||
) as EbmlCuesTagType;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
scanMeta(node: EbmlTagType): boolean {
|
seekTagBySeekId(seekId: Uint8Array): EbmlTagType | undefined {
|
||||||
if (
|
return this.seekTagByStartOffset(
|
||||||
node.id === EbmlTagIdEnum.SeekHead &&
|
this.seekOffsetBySeekId(seekId)
|
||||||
node.position === EbmlTagPosition.End
|
);
|
||||||
) {
|
|
||||||
this.addSeekHead(node);
|
|
||||||
}
|
|
||||||
this.metaBuffer.push(node);
|
|
||||||
this.metaOffsets.set(node.startOffset - this.dataOffset, node);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class CuesSystem extends StandardComponentSystem<
|
export class InfoSystem extends SegmentComponentSystemTrait<EbmlInfoTagType, typeof InfoSchema> {
|
||||||
|
override get schema() {
|
||||||
|
return InfoSchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
info!: InfoType;
|
||||||
|
|
||||||
|
prepareWithInfoTag (tag: EbmlInfoTagType) {
|
||||||
|
this.info = this.componentFromTag(tag);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ClusterSystem extends SegmentComponentSystemTrait<EbmlClusterTagType, typeof ClusterSchema> {
|
||||||
|
override get schema() {
|
||||||
|
return ClusterSchema
|
||||||
|
}
|
||||||
|
|
||||||
|
clustersBuffer: ClusterType[] = [];
|
||||||
|
|
||||||
|
addClusterWithTag (tag: EbmlClusterTagType): ClusterType {
|
||||||
|
const cluster = this.componentFromTag(tag);
|
||||||
|
this.clustersBuffer.push(cluster);
|
||||||
|
return cluster;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TrackSystem extends SegmentComponentSystemTrait<EbmlTrackEntryTagType, typeof TrackEntrySchema> {
|
||||||
|
override get schema() {
|
||||||
|
return TrackEntrySchema;
|
||||||
|
}
|
||||||
|
|
||||||
|
tracks = new Map<number, TrackEntryType>();
|
||||||
|
|
||||||
|
prepareTracksWithTag (tag: EbmlTracksTagType) {
|
||||||
|
this.tracks.clear();
|
||||||
|
for (const c of tag.children) {
|
||||||
|
if (c.id === EbmlTagIdEnum.TrackEntry) {
|
||||||
|
const trackEntry = this.componentFromTag(c);
|
||||||
|
this.tracks.set(trackEntry.TrackNumber, trackEntry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CueSystem extends SegmentComponentSystemTrait<
|
||||||
EbmlCuePointTagType,
|
EbmlCuePointTagType,
|
||||||
typeof CuePointSchema
|
typeof CuePointSchema
|
||||||
> {
|
> {
|
||||||
schema = CuePointSchema;
|
override get schema () {
|
||||||
cues: CuePointType[];
|
return CuePointSchema
|
||||||
|
};
|
||||||
|
|
||||||
constructor(cues: CuePointType[]) {
|
cues: CuePointType[] = [];
|
||||||
super();
|
|
||||||
this.cues = cues;
|
|
||||||
|
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 {
|
findClosestCue(seekTime: number): CuePointType | undefined {
|
||||||
@ -170,4 +264,19 @@ export class CuesSystem extends StandardComponentSystem<
|
|||||||
? before
|
? before
|
||||||
: after;
|
: 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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -26,8 +26,9 @@ import {
|
|||||||
withLatestFrom,
|
withLatestFrom,
|
||||||
} from 'rxjs';
|
} from 'rxjs';
|
||||||
import { createRangedStream } from '@/fetch';
|
import { createRangedStream } from '@/fetch';
|
||||||
import { EbmlSegment, Cluster, SEEK_ID_KAX_CUES, CuesSystem } from './model';
|
import { SegmentSystem, SEEK_ID_KAX_CUES, type CueSystem } from './model';
|
||||||
import { isTagIdPos } from './util';
|
import { isTagIdPos } from './util';
|
||||||
|
import type { ClusterType } from "./schema";
|
||||||
|
|
||||||
export function createRangedEbmlStream(
|
export function createRangedEbmlStream(
|
||||||
url: string,
|
url: string,
|
||||||
@ -124,12 +125,14 @@ export function createEbmlController(src: string) {
|
|||||||
|
|
||||||
const segments$ = segmentStart$.pipe(
|
const segments$ = segmentStart$.pipe(
|
||||||
map((startTag) => {
|
map((startTag) => {
|
||||||
const segment = new EbmlSegment(startTag);
|
const segment = new SegmentSystem(startTag);
|
||||||
|
const clusterSystem = segment.cluster;
|
||||||
|
const seekSystem = segment.seek;
|
||||||
|
|
||||||
const continuousReusedCluster$ = ebml$.pipe(
|
const continuousReusedCluster$ = ebml$.pipe(
|
||||||
filter(isTagIdPos(EbmlTagIdEnum.Cluster, EbmlTagPosition.End)),
|
filter(isTagIdPos(EbmlTagIdEnum.Cluster, EbmlTagPosition.End)),
|
||||||
filter((s) => s.id === EbmlTagIdEnum.Cluster),
|
filter((s) => s.id === EbmlTagIdEnum.Cluster),
|
||||||
map(Cluster.fromTag.bind(Cluster))
|
map(clusterSystem.addClusterWithTag.bind(clusterSystem))
|
||||||
);
|
);
|
||||||
|
|
||||||
const segmentEnd$ = ebml$.pipe(
|
const segmentEnd$ = ebml$.pipe(
|
||||||
@ -154,33 +157,27 @@ export function createEbmlController(src: string) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const withMeta$ = meta$.pipe(
|
const withMeta$ = meta$.pipe(
|
||||||
reduce((segment, meta) => {
|
reduce((segment, meta) => segment.scanHead(meta), segment),
|
||||||
segment.scanMeta(meta);
|
map(segment.completeHeads.bind(segment)),
|
||||||
return segment;
|
|
||||||
}, segment),
|
|
||||||
map((segment) => {
|
|
||||||
segment.markMetaEnd();
|
|
||||||
return segment;
|
|
||||||
}),
|
|
||||||
take(1),
|
take(1),
|
||||||
shareReplay(1)
|
shareReplay(1)
|
||||||
);
|
);
|
||||||
|
|
||||||
const withRemoteCues$ = withMeta$.pipe(
|
const withRemoteCues$ = withMeta$.pipe(
|
||||||
switchMap((s) => {
|
switchMap((s) => {
|
||||||
if (s.cuesNode) {
|
const cueSystem = s.cue;
|
||||||
|
const seekSystem = s.seek;
|
||||||
|
if (cueSystem.prepared) {
|
||||||
return EMPTY;
|
return EMPTY;
|
||||||
}
|
}
|
||||||
const cuesStartOffset =
|
const remoteCuesTagStartOffset = seekSystem.seekOffsetBySeekId(SEEK_ID_KAX_CUES);
|
||||||
s.dataOffset +
|
if (remoteCuesTagStartOffset! >= 0) {
|
||||||
(s.findSeekPositionBySeekId(SEEK_ID_KAX_CUES) ?? Number.NaN);
|
return createRangedEbmlStream(src, remoteCuesTagStartOffset).pipe(
|
||||||
if (cuesStartOffset >= 0) {
|
|
||||||
return createRangedEbmlStream(src, cuesStartOffset).pipe(
|
|
||||||
switchMap((req) => req.ebml$),
|
switchMap((req) => req.ebml$),
|
||||||
filter(isTagIdPos(EbmlTagIdEnum.Cues, EbmlTagPosition.End)),
|
filter(isTagIdPos(EbmlTagIdEnum.Cues, EbmlTagPosition.End)),
|
||||||
withLatestFrom(withMeta$),
|
withLatestFrom(withMeta$),
|
||||||
map(([cues, withMeta]) => {
|
map(([cues, withMeta]) => {
|
||||||
withMeta.cuesNode = cues;
|
withMeta.cue.prepareCuesWithTag(cues);
|
||||||
return withMeta;
|
return withMeta;
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
@ -192,12 +189,7 @@ export function createEbmlController(src: string) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const withLocalCues$ = withMeta$.pipe(
|
const withLocalCues$ = withMeta$.pipe(
|
||||||
switchMap((s) => {
|
switchMap((s) => s.cue.prepared ? of(s) : EMPTY),
|
||||||
if (s.cuesNode) {
|
|
||||||
return of(s);
|
|
||||||
}
|
|
||||||
return EMPTY;
|
|
||||||
}),
|
|
||||||
shareReplay(1)
|
shareReplay(1)
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -210,7 +202,7 @@ export function createEbmlController(src: string) {
|
|||||||
switchMap((empty) => (empty ? withMeta$ : EMPTY))
|
switchMap((empty) => (empty ? withMeta$ : EMPTY))
|
||||||
);
|
);
|
||||||
|
|
||||||
const seekWithoutCues = (seekTime: number): Observable<Cluster> => {
|
const seekWithoutCues = (seekTime: number): Observable<ClusterType> => {
|
||||||
const cluster$ = continuousReusedCluster$.pipe(
|
const cluster$ = continuousReusedCluster$.pipe(
|
||||||
isEmpty(),
|
isEmpty(),
|
||||||
switchMap((empty) => {
|
switchMap((empty) => {
|
||||||
@ -223,7 +215,7 @@ export function createEbmlController(src: string) {
|
|||||||
filter(
|
filter(
|
||||||
isTagIdPos(EbmlTagIdEnum.Cluster, EbmlTagPosition.End)
|
isTagIdPos(EbmlTagIdEnum.Cluster, EbmlTagPosition.End)
|
||||||
),
|
),
|
||||||
map(Cluster.fromTag.bind(Cluster))
|
map((tag) => clusterSystem.addClusterWithTag(tag))
|
||||||
)
|
)
|
||||||
: continuousReusedCluster$;
|
: continuousReusedCluster$;
|
||||||
})
|
})
|
||||||
@ -236,23 +228,23 @@ export function createEbmlController(src: string) {
|
|||||||
scan(
|
scan(
|
||||||
(prev, curr) =>
|
(prev, curr) =>
|
||||||
[prev?.[1], curr] as [
|
[prev?.[1], curr] as [
|
||||||
Cluster | undefined,
|
ClusterType | undefined,
|
||||||
Cluster | undefined,
|
ClusterType | undefined,
|
||||||
],
|
],
|
||||||
[undefined, undefined] as [
|
[undefined, undefined] as [
|
||||||
Cluster | undefined,
|
ClusterType | undefined,
|
||||||
Cluster | undefined,
|
ClusterType | undefined,
|
||||||
]
|
]
|
||||||
),
|
),
|
||||||
filter((c) => c[1]?.timestamp! > seekTime),
|
filter((c) => c[1]?.Timestamp! > seekTime),
|
||||||
map((c) => c[0] ?? c[1]!)
|
map((c) => c[0] ?? c[1]!)
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const seekWithCues = (
|
const seekWithCues = (
|
||||||
cues: CuesSystem,
|
cues: CueSystem,
|
||||||
seekTime: number
|
seekTime: number
|
||||||
): Observable<Cluster> => {
|
): Observable<ClusterType> => {
|
||||||
if (seekTime === 0) {
|
if (seekTime === 0) {
|
||||||
return seekWithoutCues(seekTime);
|
return seekWithoutCues(seekTime);
|
||||||
}
|
}
|
||||||
@ -265,29 +257,29 @@ export function createEbmlController(src: string) {
|
|||||||
|
|
||||||
return createRangedEbmlStream(
|
return createRangedEbmlStream(
|
||||||
src,
|
src,
|
||||||
cuePoint.position + segment.dataOffset
|
seekSystem.offsetFromSeekDataPosition(cues.getCueTrackPositions(cuePoint).CueClusterPosition)
|
||||||
).pipe(
|
).pipe(
|
||||||
switchMap((req) => req.ebml$),
|
switchMap((req) => req.ebml$),
|
||||||
filter(isTagIdPos(EbmlTagIdEnum.Cluster, EbmlTagPosition.End)),
|
filter(isTagIdPos(EbmlTagIdEnum.Cluster, EbmlTagPosition.End)),
|
||||||
map(Cluster.fromTag.bind(Cluster))
|
map(clusterSystem.addClusterWithTag.bind(clusterSystem))
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const seek = (seekTime: number): Observable<Cluster> => {
|
const seek = (seekTime: number): Observable<ClusterType> => {
|
||||||
if (seekTime === 0) {
|
if (seekTime === 0) {
|
||||||
const subscripton = merge(withCues$, withoutCues$).subscribe();
|
const subscription = merge(withCues$, withoutCues$).subscribe();
|
||||||
|
|
||||||
// if seekTime equals to 0 at start, reuse the initialize stream
|
// if seekTime equals to 0 at start, reuse the initialize stream
|
||||||
return seekWithoutCues(seekTime).pipe(
|
return seekWithoutCues(seekTime).pipe(
|
||||||
finalize(() => {
|
finalize(() => {
|
||||||
subscripton.unsubscribe();
|
subscription.unsubscribe();
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
return merge(
|
return merge(
|
||||||
withCues$.pipe(
|
withCues$.pipe(
|
||||||
switchMap((s) =>
|
switchMap((s) =>
|
||||||
seekWithCues(CuesSystem.fromTag(s.cuesNode!), seekTime)
|
seekWithCues(s.cue, seekTime)
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
withoutCues$.pipe(switchMap((_) => seekWithoutCues(seekTime)))
|
withoutCues$.pipe(switchMap((_) => seekWithoutCues(seekTime)))
|
||||||
|
@ -33,7 +33,7 @@ export const SeekSchema = type({
|
|||||||
export type SeekType = typeof SeekSchema.infer;
|
export type SeekType = typeof SeekSchema.infer;
|
||||||
|
|
||||||
export const SeekHeadSchema = type({
|
export const SeekHeadSchema = type({
|
||||||
Seek: SeekSchema.array(),
|
Seek: SeekSchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type SeekHeadType = typeof SeekHeadSchema.infer;
|
export type SeekHeadType = typeof SeekHeadSchema.infer;
|
||||||
@ -79,7 +79,7 @@ export const BlockMoreSchema = type({
|
|||||||
export type BlockMoreType = typeof BlockMoreSchema.infer;
|
export type BlockMoreType = typeof BlockMoreSchema.infer;
|
||||||
|
|
||||||
export const BlockAdditionsSchema = type({
|
export const BlockAdditionsSchema = type({
|
||||||
BlockMore: BlockMoreSchema.array(),
|
BlockMore: BlockMoreSchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type BlockAdditionsType = typeof BlockAdditionsSchema.infer;
|
export type BlockAdditionsType = typeof BlockAdditionsSchema.infer;
|
||||||
@ -198,12 +198,9 @@ export enum MatrixCoefficientsRestrictionEnum {
|
|||||||
CHROMA_DERIVED_CONSTANT_LUMINANCE = 13,
|
CHROMA_DERIVED_CONSTANT_LUMINANCE = 13,
|
||||||
// ITU-R BT.2100-0
|
// ITU-R BT.2100-0
|
||||||
ITU_R_BT_2100_0 = 14,
|
ITU_R_BT_2100_0 = 14,
|
||||||
}
|
};
|
||||||
export const MatrixCoefficientsRestriction = type(
|
export const MatrixCoefficientsRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14');
|
||||||
'0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14'
|
export type MatrixCoefficientsRestrictionType = typeof MatrixCoefficientsRestriction.infer;
|
||||||
);
|
|
||||||
export type MatrixCoefficientsRestrictionType =
|
|
||||||
typeof MatrixCoefficientsRestriction.infer;
|
|
||||||
|
|
||||||
export enum ChromaSitingHorzRestrictionEnum {
|
export enum ChromaSitingHorzRestrictionEnum {
|
||||||
// unspecified
|
// unspecified
|
||||||
@ -212,10 +209,9 @@ export enum ChromaSitingHorzRestrictionEnum {
|
|||||||
LEFT_COLLOCATED = 1,
|
LEFT_COLLOCATED = 1,
|
||||||
// half
|
// half
|
||||||
HALF = 2,
|
HALF = 2,
|
||||||
}
|
};
|
||||||
export const ChromaSitingHorzRestriction = type('0 | 1 | 2');
|
export const ChromaSitingHorzRestriction = type('0 | 1 | 2');
|
||||||
export type ChromaSitingHorzRestrictionType =
|
export type ChromaSitingHorzRestrictionType = typeof ChromaSitingHorzRestriction.infer;
|
||||||
typeof ChromaSitingHorzRestriction.infer;
|
|
||||||
|
|
||||||
export enum ChromaSitingVertRestrictionEnum {
|
export enum ChromaSitingVertRestrictionEnum {
|
||||||
// unspecified
|
// unspecified
|
||||||
@ -224,10 +220,9 @@ export enum ChromaSitingVertRestrictionEnum {
|
|||||||
TOP_COLLOCATED = 1,
|
TOP_COLLOCATED = 1,
|
||||||
// half
|
// half
|
||||||
HALF = 2,
|
HALF = 2,
|
||||||
}
|
};
|
||||||
export const ChromaSitingVertRestriction = type('0 | 1 | 2');
|
export const ChromaSitingVertRestriction = type('0 | 1 | 2');
|
||||||
export type ChromaSitingVertRestrictionType =
|
export type ChromaSitingVertRestrictionType = typeof ChromaSitingVertRestriction.infer;
|
||||||
typeof ChromaSitingVertRestriction.infer;
|
|
||||||
|
|
||||||
export enum RangeRestrictionEnum {
|
export enum RangeRestrictionEnum {
|
||||||
// unspecified
|
// unspecified
|
||||||
@ -238,7 +233,7 @@ export enum RangeRestrictionEnum {
|
|||||||
FULL_RANGE_NO_CLIPPING = 2,
|
FULL_RANGE_NO_CLIPPING = 2,
|
||||||
// defined by MatrixCoefficients / TransferCharacteristics
|
// defined by MatrixCoefficients / TransferCharacteristics
|
||||||
DEFINED_BY_MATRIX_COEFFICIENTS_TRANSFER_CHARACTERISTICS = 3,
|
DEFINED_BY_MATRIX_COEFFICIENTS_TRANSFER_CHARACTERISTICS = 3,
|
||||||
}
|
};
|
||||||
export const RangeRestriction = type('0 | 1 | 2 | 3');
|
export const RangeRestriction = type('0 | 1 | 2 | 3');
|
||||||
export type RangeRestrictionType = typeof RangeRestriction.infer;
|
export type RangeRestrictionType = typeof RangeRestriction.infer;
|
||||||
|
|
||||||
@ -281,12 +276,9 @@ export enum TransferCharacteristicsRestrictionEnum {
|
|||||||
SMPTE_ST_428_1 = 17,
|
SMPTE_ST_428_1 = 17,
|
||||||
// ARIB STD-B67 (HLG)
|
// ARIB STD-B67 (HLG)
|
||||||
ARIB_STD_B67_HLG = 18,
|
ARIB_STD_B67_HLG = 18,
|
||||||
}
|
};
|
||||||
export const TransferCharacteristicsRestriction = type(
|
export const TransferCharacteristicsRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18');
|
||||||
'0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18'
|
export type TransferCharacteristicsRestrictionType = typeof TransferCharacteristicsRestriction.infer;
|
||||||
);
|
|
||||||
export type TransferCharacteristicsRestrictionType =
|
|
||||||
typeof TransferCharacteristicsRestriction.infer;
|
|
||||||
|
|
||||||
export enum PrimariesRestrictionEnum {
|
export enum PrimariesRestrictionEnum {
|
||||||
// reserved
|
// reserved
|
||||||
@ -317,10 +309,8 @@ export enum PrimariesRestrictionEnum {
|
|||||||
SMPTE_EG_432_2 = 12,
|
SMPTE_EG_432_2 = 12,
|
||||||
// EBU Tech. 3213-E - JEDEC P22 phosphors
|
// EBU Tech. 3213-E - JEDEC P22 phosphors
|
||||||
EBU_TECH_3213_E_JEDEC_P22_PHOSPHORS = 22,
|
EBU_TECH_3213_E_JEDEC_P22_PHOSPHORS = 22,
|
||||||
}
|
};
|
||||||
export const PrimariesRestriction = type(
|
export const PrimariesRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 22');
|
||||||
'0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 22'
|
|
||||||
);
|
|
||||||
export type PrimariesRestrictionType = typeof PrimariesRestriction.infer;
|
export type PrimariesRestrictionType = typeof PrimariesRestriction.infer;
|
||||||
|
|
||||||
export const ColourSchema = type({
|
export const ColourSchema = type({
|
||||||
@ -351,10 +341,9 @@ export enum ProjectionTypeRestrictionEnum {
|
|||||||
CUBEMAP = 2,
|
CUBEMAP = 2,
|
||||||
// mesh
|
// mesh
|
||||||
MESH = 3,
|
MESH = 3,
|
||||||
}
|
};
|
||||||
export const ProjectionTypeRestriction = type('0 | 1 | 2 | 3');
|
export const ProjectionTypeRestriction = type('0 | 1 | 2 | 3');
|
||||||
export type ProjectionTypeRestrictionType =
|
export type ProjectionTypeRestrictionType = typeof ProjectionTypeRestriction.infer;
|
||||||
typeof ProjectionTypeRestriction.infer;
|
|
||||||
|
|
||||||
export const ProjectionSchema = type({
|
export const ProjectionSchema = type({
|
||||||
ProjectionType: ProjectionTypeRestriction.default(0),
|
ProjectionType: ProjectionTypeRestriction.default(0),
|
||||||
@ -373,10 +362,9 @@ export enum FlagInterlacedRestrictionEnum {
|
|||||||
INTERLACED = 1,
|
INTERLACED = 1,
|
||||||
// progressive
|
// progressive
|
||||||
PROGRESSIVE = 2,
|
PROGRESSIVE = 2,
|
||||||
}
|
};
|
||||||
export const FlagInterlacedRestriction = type('0 | 1 | 2');
|
export const FlagInterlacedRestriction = type('0 | 1 | 2');
|
||||||
export type FlagInterlacedRestrictionType =
|
export type FlagInterlacedRestrictionType = typeof FlagInterlacedRestriction.infer;
|
||||||
typeof FlagInterlacedRestriction.infer;
|
|
||||||
|
|
||||||
export enum FieldOrderRestrictionEnum {
|
export enum FieldOrderRestrictionEnum {
|
||||||
// progressive
|
// progressive
|
||||||
@ -391,7 +379,7 @@ export enum FieldOrderRestrictionEnum {
|
|||||||
TFF_INTERLEAVED = 9,
|
TFF_INTERLEAVED = 9,
|
||||||
// bff (interleaved)
|
// bff (interleaved)
|
||||||
BFF_INTERLEAVED = 14,
|
BFF_INTERLEAVED = 14,
|
||||||
}
|
};
|
||||||
export const FieldOrderRestriction = type('0 | 1 | 2 | 6 | 9 | 14');
|
export const FieldOrderRestriction = type('0 | 1 | 2 | 6 | 9 | 14');
|
||||||
export type FieldOrderRestrictionType = typeof FieldOrderRestriction.infer;
|
export type FieldOrderRestrictionType = typeof FieldOrderRestriction.infer;
|
||||||
|
|
||||||
@ -426,10 +414,8 @@ export enum StereoModeRestrictionEnum {
|
|||||||
BOTH_EYES_LACED_IN_ONE_BLOCK_LEFT_EYE_IS_FIRST = 13,
|
BOTH_EYES_LACED_IN_ONE_BLOCK_LEFT_EYE_IS_FIRST = 13,
|
||||||
// both eyes laced in one Block (right eye is first)
|
// both eyes laced in one Block (right eye is first)
|
||||||
BOTH_EYES_LACED_IN_ONE_BLOCK_RIGHT_EYE_IS_FIRST = 14,
|
BOTH_EYES_LACED_IN_ONE_BLOCK_RIGHT_EYE_IS_FIRST = 14,
|
||||||
}
|
};
|
||||||
export const StereoModeRestriction = type(
|
export const StereoModeRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14');
|
||||||
'0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14'
|
|
||||||
);
|
|
||||||
export type StereoModeRestrictionType = typeof StereoModeRestriction.infer;
|
export type StereoModeRestrictionType = typeof StereoModeRestriction.infer;
|
||||||
|
|
||||||
export enum AlphaModeRestrictionEnum {
|
export enum AlphaModeRestrictionEnum {
|
||||||
@ -437,7 +423,7 @@ export enum AlphaModeRestrictionEnum {
|
|||||||
NONE = 0,
|
NONE = 0,
|
||||||
// present
|
// present
|
||||||
PRESENT = 1,
|
PRESENT = 1,
|
||||||
}
|
};
|
||||||
export const AlphaModeRestriction = type('0 | 1');
|
export const AlphaModeRestriction = type('0 | 1');
|
||||||
export type AlphaModeRestrictionType = typeof AlphaModeRestriction.infer;
|
export type AlphaModeRestrictionType = typeof AlphaModeRestriction.infer;
|
||||||
|
|
||||||
@ -450,10 +436,9 @@ export enum OldStereoModeRestrictionEnum {
|
|||||||
LEFT_EYE = 2,
|
LEFT_EYE = 2,
|
||||||
// both eyes
|
// both eyes
|
||||||
BOTH_EYES = 3,
|
BOTH_EYES = 3,
|
||||||
}
|
};
|
||||||
export const OldStereoModeRestriction = type('0 | 1 | 2 | 3');
|
export const OldStereoModeRestriction = type('0 | 1 | 2 | 3');
|
||||||
export type OldStereoModeRestrictionType =
|
export type OldStereoModeRestrictionType = typeof OldStereoModeRestriction.infer;
|
||||||
typeof OldStereoModeRestriction.infer;
|
|
||||||
|
|
||||||
export enum DisplayUnitRestrictionEnum {
|
export enum DisplayUnitRestrictionEnum {
|
||||||
// pixels
|
// pixels
|
||||||
@ -466,7 +451,7 @@ export enum DisplayUnitRestrictionEnum {
|
|||||||
DISPLAY_ASPECT_RATIO = 3,
|
DISPLAY_ASPECT_RATIO = 3,
|
||||||
// unknown
|
// unknown
|
||||||
UNKNOWN = 4,
|
UNKNOWN = 4,
|
||||||
}
|
};
|
||||||
export const DisplayUnitRestriction = type('0 | 1 | 2 | 3 | 4');
|
export const DisplayUnitRestriction = type('0 | 1 | 2 | 3 | 4');
|
||||||
export type DisplayUnitRestrictionType = typeof DisplayUnitRestriction.infer;
|
export type DisplayUnitRestrictionType = typeof DisplayUnitRestriction.infer;
|
||||||
|
|
||||||
@ -477,10 +462,9 @@ export enum AspectRatioTypeRestrictionEnum {
|
|||||||
KEEP_ASPECT_RATIO = 1,
|
KEEP_ASPECT_RATIO = 1,
|
||||||
// fixed
|
// fixed
|
||||||
FIXED = 2,
|
FIXED = 2,
|
||||||
}
|
};
|
||||||
export const AspectRatioTypeRestriction = type('0 | 1 | 2');
|
export const AspectRatioTypeRestriction = type('0 | 1 | 2');
|
||||||
export type AspectRatioTypeRestrictionType =
|
export type AspectRatioTypeRestrictionType = typeof AspectRatioTypeRestriction.infer;
|
||||||
typeof AspectRatioTypeRestriction.infer;
|
|
||||||
|
|
||||||
export const VideoSchema = type({
|
export const VideoSchema = type({
|
||||||
FlagInterlaced: FlagInterlacedRestriction.default(0),
|
FlagInterlaced: FlagInterlacedRestriction.default(0),
|
||||||
@ -534,10 +518,8 @@ export enum EmphasisRestrictionEnum {
|
|||||||
PHONO_LONDON = 15,
|
PHONO_LONDON = 15,
|
||||||
// Phono NARTB
|
// Phono NARTB
|
||||||
PHONO_NARTB = 16,
|
PHONO_NARTB = 16,
|
||||||
}
|
};
|
||||||
export const EmphasisRestriction = type(
|
export const EmphasisRestriction = type('0 | 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16');
|
||||||
'0 | 1 | 2 | 3 | 4 | 5 | 10 | 11 | 12 | 13 | 14 | 15 | 16'
|
|
||||||
);
|
|
||||||
export type EmphasisRestrictionType = typeof EmphasisRestriction.infer;
|
export type EmphasisRestrictionType = typeof EmphasisRestriction.infer;
|
||||||
|
|
||||||
export const AudioSchema = type({
|
export const AudioSchema = type({
|
||||||
@ -558,10 +540,9 @@ export enum TrackPlaneTypeRestrictionEnum {
|
|||||||
RIGHT_EYE = 1,
|
RIGHT_EYE = 1,
|
||||||
// background
|
// background
|
||||||
BACKGROUND = 2,
|
BACKGROUND = 2,
|
||||||
}
|
};
|
||||||
export const TrackPlaneTypeRestriction = type('0 | 1 | 2');
|
export const TrackPlaneTypeRestriction = type('0 | 1 | 2');
|
||||||
export type TrackPlaneTypeRestrictionType =
|
export type TrackPlaneTypeRestrictionType = typeof TrackPlaneTypeRestriction.infer;
|
||||||
typeof TrackPlaneTypeRestriction.infer;
|
|
||||||
|
|
||||||
export const TrackPlaneSchema = type({
|
export const TrackPlaneSchema = type({
|
||||||
TrackPlaneUID: type.number,
|
TrackPlaneUID: type.number,
|
||||||
@ -571,13 +552,13 @@ export const TrackPlaneSchema = type({
|
|||||||
export type TrackPlaneType = typeof TrackPlaneSchema.infer;
|
export type TrackPlaneType = typeof TrackPlaneSchema.infer;
|
||||||
|
|
||||||
export const TrackCombinePlanesSchema = type({
|
export const TrackCombinePlanesSchema = type({
|
||||||
TrackPlane: TrackPlaneSchema.array(),
|
TrackPlane: TrackPlaneSchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TrackCombinePlanesType = typeof TrackCombinePlanesSchema.infer;
|
export type TrackCombinePlanesType = typeof TrackCombinePlanesSchema.infer;
|
||||||
|
|
||||||
export const TrackJoinBlocksSchema = type({
|
export const TrackJoinBlocksSchema = type({
|
||||||
TrackJoinUID: type.number.array(),
|
TrackJoinUID: type.number.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TrackJoinBlocksType = typeof TrackJoinBlocksSchema.infer;
|
export type TrackJoinBlocksType = typeof TrackJoinBlocksSchema.infer;
|
||||||
@ -598,10 +579,9 @@ export enum ContentCompAlgoRestrictionEnum {
|
|||||||
LZO1X = 2,
|
LZO1X = 2,
|
||||||
// Header Stripping
|
// Header Stripping
|
||||||
HEADER_STRIPPING = 3,
|
HEADER_STRIPPING = 3,
|
||||||
}
|
};
|
||||||
export const ContentCompAlgoRestriction = type('0 | 1 | 2 | 3');
|
export const ContentCompAlgoRestriction = type('0 | 1 | 2 | 3');
|
||||||
export type ContentCompAlgoRestrictionType =
|
export type ContentCompAlgoRestrictionType = typeof ContentCompAlgoRestriction.infer;
|
||||||
typeof ContentCompAlgoRestriction.infer;
|
|
||||||
|
|
||||||
export const ContentCompressionSchema = type({
|
export const ContentCompressionSchema = type({
|
||||||
ContentCompAlgo: ContentCompAlgoRestriction.default(0),
|
ContentCompAlgo: ContentCompAlgoRestriction.default(0),
|
||||||
@ -615,17 +595,15 @@ export enum AESSettingsCipherModeRestrictionEnum {
|
|||||||
AES_CTR = 1,
|
AES_CTR = 1,
|
||||||
// AES-CBC
|
// AES-CBC
|
||||||
AES_CBC = 2,
|
AES_CBC = 2,
|
||||||
}
|
};
|
||||||
export const AESSettingsCipherModeRestriction = type('1 | 2');
|
export const AESSettingsCipherModeRestriction = type('1 | 2');
|
||||||
export type AESSettingsCipherModeRestrictionType =
|
export type AESSettingsCipherModeRestrictionType = typeof AESSettingsCipherModeRestriction.infer;
|
||||||
typeof AESSettingsCipherModeRestriction.infer;
|
|
||||||
|
|
||||||
export const ContentEncAESSettingsSchema = type({
|
export const ContentEncAESSettingsSchema = type({
|
||||||
AESSettingsCipherMode: AESSettingsCipherModeRestriction,
|
AESSettingsCipherMode: AESSettingsCipherModeRestriction,
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ContentEncAESSettingsType =
|
export type ContentEncAESSettingsType = typeof ContentEncAESSettingsSchema.infer;
|
||||||
typeof ContentEncAESSettingsSchema.infer;
|
|
||||||
|
|
||||||
export enum ContentEncAlgoRestrictionEnum {
|
export enum ContentEncAlgoRestrictionEnum {
|
||||||
// Not encrypted
|
// Not encrypted
|
||||||
@ -640,20 +618,18 @@ export enum ContentEncAlgoRestrictionEnum {
|
|||||||
BLOWFISH = 4,
|
BLOWFISH = 4,
|
||||||
// AES
|
// AES
|
||||||
AES = 5,
|
AES = 5,
|
||||||
}
|
};
|
||||||
export const ContentEncAlgoRestriction = type('0 | 1 | 2 | 3 | 4 | 5');
|
export const ContentEncAlgoRestriction = type('0 | 1 | 2 | 3 | 4 | 5');
|
||||||
export type ContentEncAlgoRestrictionType =
|
export type ContentEncAlgoRestrictionType = typeof ContentEncAlgoRestriction.infer;
|
||||||
typeof ContentEncAlgoRestriction.infer;
|
|
||||||
|
|
||||||
export enum ContentSigAlgoRestrictionEnum {
|
export enum ContentSigAlgoRestrictionEnum {
|
||||||
// Not signed
|
// Not signed
|
||||||
NOT_SIGNED = 0,
|
NOT_SIGNED = 0,
|
||||||
// RSA
|
// RSA
|
||||||
RSA = 1,
|
RSA = 1,
|
||||||
}
|
};
|
||||||
export const ContentSigAlgoRestriction = type('0 | 1');
|
export const ContentSigAlgoRestriction = type('0 | 1');
|
||||||
export type ContentSigAlgoRestrictionType =
|
export type ContentSigAlgoRestrictionType = typeof ContentSigAlgoRestriction.infer;
|
||||||
typeof ContentSigAlgoRestriction.infer;
|
|
||||||
|
|
||||||
export enum ContentSigHashAlgoRestrictionEnum {
|
export enum ContentSigHashAlgoRestrictionEnum {
|
||||||
// Not signed
|
// Not signed
|
||||||
@ -662,10 +638,9 @@ export enum ContentSigHashAlgoRestrictionEnum {
|
|||||||
SHA1_160 = 1,
|
SHA1_160 = 1,
|
||||||
// MD5
|
// MD5
|
||||||
MD5 = 2,
|
MD5 = 2,
|
||||||
}
|
};
|
||||||
export const ContentSigHashAlgoRestriction = type('0 | 1 | 2');
|
export const ContentSigHashAlgoRestriction = type('0 | 1 | 2');
|
||||||
export type ContentSigHashAlgoRestrictionType =
|
export type ContentSigHashAlgoRestrictionType = typeof ContentSigHashAlgoRestriction.infer;
|
||||||
typeof ContentSigHashAlgoRestriction.infer;
|
|
||||||
|
|
||||||
export const ContentEncryptionSchema = type({
|
export const ContentEncryptionSchema = type({
|
||||||
ContentEncAlgo: ContentEncAlgoRestriction.default(0),
|
ContentEncAlgo: ContentEncAlgoRestriction.default(0),
|
||||||
@ -686,20 +661,18 @@ export enum ContentEncodingScopeRestrictionEnum {
|
|||||||
PRIVATE = 2,
|
PRIVATE = 2,
|
||||||
// Next
|
// Next
|
||||||
NEXT = 4,
|
NEXT = 4,
|
||||||
}
|
};
|
||||||
export const ContentEncodingScopeRestriction = type('1 | 2 | 4');
|
export const ContentEncodingScopeRestriction = type('1 | 2 | 4');
|
||||||
export type ContentEncodingScopeRestrictionType =
|
export type ContentEncodingScopeRestrictionType = typeof ContentEncodingScopeRestriction.infer;
|
||||||
typeof ContentEncodingScopeRestriction.infer;
|
|
||||||
|
|
||||||
export enum ContentEncodingTypeRestrictionEnum {
|
export enum ContentEncodingTypeRestrictionEnum {
|
||||||
// Compression
|
// Compression
|
||||||
COMPRESSION = 0,
|
COMPRESSION = 0,
|
||||||
// Encryption
|
// Encryption
|
||||||
ENCRYPTION = 1,
|
ENCRYPTION = 1,
|
||||||
}
|
};
|
||||||
export const ContentEncodingTypeRestriction = type('0 | 1');
|
export const ContentEncodingTypeRestriction = type('0 | 1');
|
||||||
export type ContentEncodingTypeRestrictionType =
|
export type ContentEncodingTypeRestrictionType = typeof ContentEncodingTypeRestriction.infer;
|
||||||
typeof ContentEncodingTypeRestriction.infer;
|
|
||||||
|
|
||||||
export const ContentEncodingSchema = type({
|
export const ContentEncodingSchema = type({
|
||||||
ContentEncodingOrder: type.number.default(0),
|
ContentEncodingOrder: type.number.default(0),
|
||||||
@ -712,7 +685,7 @@ export const ContentEncodingSchema = type({
|
|||||||
export type ContentEncodingType = typeof ContentEncodingSchema.infer;
|
export type ContentEncodingType = typeof ContentEncodingSchema.infer;
|
||||||
|
|
||||||
export const ContentEncodingsSchema = type({
|
export const ContentEncodingsSchema = type({
|
||||||
ContentEncoding: ContentEncodingSchema.array(),
|
ContentEncoding: ContentEncodingSchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ContentEncodingsType = typeof ContentEncodingsSchema.infer;
|
export type ContentEncodingsType = typeof ContentEncodingsSchema.infer;
|
||||||
@ -734,7 +707,7 @@ export enum TrackTypeRestrictionEnum {
|
|||||||
CONTROL = 32,
|
CONTROL = 32,
|
||||||
// metadata
|
// metadata
|
||||||
METADATA = 33,
|
METADATA = 33,
|
||||||
}
|
};
|
||||||
export const TrackTypeRestriction = type('1 | 2 | 3 | 16 | 17 | 18 | 32 | 33');
|
export const TrackTypeRestriction = type('1 | 2 | 3 | 16 | 17 | 18 | 32 | 33');
|
||||||
export type TrackTypeRestrictionType = typeof TrackTypeRestriction.infer;
|
export type TrackTypeRestrictionType = typeof TrackTypeRestriction.infer;
|
||||||
|
|
||||||
@ -760,7 +733,7 @@ export const TrackEntrySchema = type({
|
|||||||
MaxBlockAdditionID: type.number.default(0),
|
MaxBlockAdditionID: type.number.default(0),
|
||||||
BlockAdditionMapping: BlockAdditionMappingSchema.array().optional(),
|
BlockAdditionMapping: BlockAdditionMappingSchema.array().optional(),
|
||||||
Name: type.string.optional(),
|
Name: type.string.optional(),
|
||||||
Language: type.string.default('eng'),
|
Language: type.string.default("eng"),
|
||||||
LanguageBCP47: type.string.optional(),
|
LanguageBCP47: type.string.optional(),
|
||||||
CodecID: type.string,
|
CodecID: type.string,
|
||||||
CodecPrivate: BinarySchema.optional(),
|
CodecPrivate: BinarySchema.optional(),
|
||||||
@ -788,7 +761,7 @@ export const TrackEntrySchema = type({
|
|||||||
export type TrackEntryType = typeof TrackEntrySchema.infer;
|
export type TrackEntryType = typeof TrackEntrySchema.infer;
|
||||||
|
|
||||||
export const TracksSchema = type({
|
export const TracksSchema = type({
|
||||||
TrackEntry: TrackEntrySchema.array(),
|
TrackEntry: TrackEntrySchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TracksType = typeof TracksSchema.infer;
|
export type TracksType = typeof TracksSchema.infer;
|
||||||
@ -816,13 +789,13 @@ export type CueTrackPositionsType = typeof CueTrackPositionsSchema.infer;
|
|||||||
|
|
||||||
export const CuePointSchema = type({
|
export const CuePointSchema = type({
|
||||||
CueTime: type.number,
|
CueTime: type.number,
|
||||||
CueTrackPositions: CueTrackPositionsSchema.array(),
|
CueTrackPositions: CueTrackPositionsSchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CuePointType = typeof CuePointSchema.infer;
|
export type CuePointType = typeof CuePointSchema.infer;
|
||||||
|
|
||||||
export const CuesSchema = type({
|
export const CuesSchema = type({
|
||||||
CuePoint: CuePointSchema.array(),
|
CuePoint: CuePointSchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CuesType = typeof CuesSchema.infer;
|
export type CuesType = typeof CuesSchema.infer;
|
||||||
@ -841,7 +814,7 @@ export const AttachedFileSchema = type({
|
|||||||
export type AttachedFileType = typeof AttachedFileSchema.infer;
|
export type AttachedFileType = typeof AttachedFileSchema.infer;
|
||||||
|
|
||||||
export const AttachmentsSchema = type({
|
export const AttachmentsSchema = type({
|
||||||
AttachedFile: AttachedFileSchema.array(),
|
AttachedFile: AttachedFileSchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type AttachmentsType = typeof AttachmentsSchema.infer;
|
export type AttachmentsType = typeof AttachmentsSchema.infer;
|
||||||
@ -859,38 +832,39 @@ export const EditionEntrySchema = type({
|
|||||||
EditionFlagDefault: type.number.default(0),
|
EditionFlagDefault: type.number.default(0),
|
||||||
EditionFlagOrdered: type.number.default(0),
|
EditionFlagOrdered: type.number.default(0),
|
||||||
EditionDisplay: EditionDisplaySchema.array().optional(),
|
EditionDisplay: EditionDisplaySchema.array().optional(),
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type EditionEntryType = typeof EditionEntrySchema.infer;
|
export type EditionEntryType = typeof EditionEntrySchema.infer;
|
||||||
|
|
||||||
export const ChaptersSchema = type({
|
export const ChaptersSchema = type({
|
||||||
EditionEntry: EditionEntrySchema.array(),
|
EditionEntry: EditionEntrySchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ChaptersType = typeof ChaptersSchema.infer;
|
export type ChaptersType = typeof ChaptersSchema.infer;
|
||||||
|
|
||||||
export const TagTrackUIDSchema = match({
|
export const TagTrackUIDSchema = match({
|
||||||
'number[]': (v) => (v.length > 0 ? v : [0]),
|
"number[]": v => v.length > 0 ? v : [0],
|
||||||
undefined: () => [0],
|
"undefined": () => [0],
|
||||||
default: 'assert',
|
default: "assert"
|
||||||
});
|
});
|
||||||
|
|
||||||
export const TagEditionUIDSchema = match({
|
export const TagEditionUIDSchema = match({
|
||||||
'number[]': (v) => (v.length > 0 ? v : [0]),
|
"number[]": v => v.length > 0 ? v : [0],
|
||||||
undefined: () => [0],
|
"undefined": () => [0],
|
||||||
default: 'assert',
|
default: "assert"
|
||||||
});
|
});
|
||||||
|
|
||||||
export const TagChapterUIDSchema = match({
|
export const TagChapterUIDSchema = match({
|
||||||
'number[]': (v) => (v.length > 0 ? v : [0]),
|
"number[]": v => v.length > 0 ? v : [0],
|
||||||
undefined: () => [0],
|
"undefined": () => [0],
|
||||||
default: 'assert',
|
default: "assert"
|
||||||
});
|
});
|
||||||
|
|
||||||
export const TagAttachmentUIDSchema = match({
|
export const TagAttachmentUIDSchema = match({
|
||||||
'number[]': (v) => (v.length > 0 ? v : [0]),
|
"number[]": v => v.length > 0 ? v : [0],
|
||||||
undefined: () => [0],
|
"undefined": () => [0],
|
||||||
default: 'assert',
|
default: "assert"
|
||||||
});
|
});
|
||||||
|
|
||||||
export enum TargetTypeValueRestrictionEnum {
|
export enum TargetTypeValueRestrictionEnum {
|
||||||
@ -908,60 +882,55 @@ export enum TargetTypeValueRestrictionEnum {
|
|||||||
EDITION_ISSUE_VOLUME_OPUS_SEASON_SEQUEL = 60,
|
EDITION_ISSUE_VOLUME_OPUS_SEASON_SEQUEL = 60,
|
||||||
// COLLECTION
|
// COLLECTION
|
||||||
COLLECTION = 70,
|
COLLECTION = 70,
|
||||||
}
|
};
|
||||||
export const TargetTypeValueRestriction = type(
|
export const TargetTypeValueRestriction = type('10 | 20 | 30 | 40 | 50 | 60 | 70');
|
||||||
'10 | 20 | 30 | 40 | 50 | 60 | 70'
|
export type TargetTypeValueRestrictionType = typeof TargetTypeValueRestriction.infer;
|
||||||
);
|
|
||||||
export type TargetTypeValueRestrictionType =
|
|
||||||
typeof TargetTypeValueRestriction.infer;
|
|
||||||
|
|
||||||
export enum TargetTypeRestrictionEnum {
|
export enum TargetTypeRestrictionEnum {
|
||||||
// TargetTypeValue 70
|
// TargetTypeValue 70
|
||||||
COLLECTION = 'COLLECTION',
|
COLLECTION = "COLLECTION",
|
||||||
// TargetTypeValue 60
|
// TargetTypeValue 60
|
||||||
EDITION = 'EDITION',
|
EDITION = "EDITION",
|
||||||
// TargetTypeValue 60
|
// TargetTypeValue 60
|
||||||
ISSUE = 'ISSUE',
|
ISSUE = "ISSUE",
|
||||||
// TargetTypeValue 60
|
// TargetTypeValue 60
|
||||||
VOLUME = 'VOLUME',
|
VOLUME = "VOLUME",
|
||||||
// TargetTypeValue 60
|
// TargetTypeValue 60
|
||||||
OPUS = 'OPUS',
|
OPUS = "OPUS",
|
||||||
// TargetTypeValue 60
|
// TargetTypeValue 60
|
||||||
SEASON = 'SEASON',
|
SEASON = "SEASON",
|
||||||
// TargetTypeValue 60
|
// TargetTypeValue 60
|
||||||
SEQUEL = 'SEQUEL',
|
SEQUEL = "SEQUEL",
|
||||||
// TargetTypeValue 50
|
// TargetTypeValue 50
|
||||||
ALBUM = 'ALBUM',
|
ALBUM = "ALBUM",
|
||||||
// TargetTypeValue 50
|
// TargetTypeValue 50
|
||||||
OPERA = 'OPERA',
|
OPERA = "OPERA",
|
||||||
// TargetTypeValue 50
|
// TargetTypeValue 50
|
||||||
CONCERT = 'CONCERT',
|
CONCERT = "CONCERT",
|
||||||
// TargetTypeValue 50
|
// TargetTypeValue 50
|
||||||
MOVIE = 'MOVIE',
|
MOVIE = "MOVIE",
|
||||||
// TargetTypeValue 50
|
// TargetTypeValue 50
|
||||||
EPISODE = 'EPISODE',
|
EPISODE = "EPISODE",
|
||||||
// TargetTypeValue 40
|
// TargetTypeValue 40
|
||||||
PART = 'PART',
|
PART = "PART",
|
||||||
// TargetTypeValue 40
|
// TargetTypeValue 40
|
||||||
SESSION = 'SESSION',
|
SESSION = "SESSION",
|
||||||
// TargetTypeValue 30
|
// TargetTypeValue 30
|
||||||
TRACK = 'TRACK',
|
TRACK = "TRACK",
|
||||||
// TargetTypeValue 30
|
// TargetTypeValue 30
|
||||||
SONG = 'SONG',
|
SONG = "SONG",
|
||||||
// TargetTypeValue 30
|
// TargetTypeValue 30
|
||||||
CHAPTER = 'CHAPTER',
|
CHAPTER = "CHAPTER",
|
||||||
// TargetTypeValue 20
|
// TargetTypeValue 20
|
||||||
SUBTRACK = 'SUBTRACK',
|
SUBTRACK = "SUBTRACK",
|
||||||
// TargetTypeValue 20
|
// TargetTypeValue 20
|
||||||
MOVEMENT = 'MOVEMENT',
|
MOVEMENT = "MOVEMENT",
|
||||||
// TargetTypeValue 20
|
// TargetTypeValue 20
|
||||||
SCENE = 'SCENE',
|
SCENE = "SCENE",
|
||||||
// TargetTypeValue 10
|
// TargetTypeValue 10
|
||||||
SHOT = 'SHOT',
|
SHOT = "SHOT",
|
||||||
}
|
};
|
||||||
export const TargetTypeRestriction = type(
|
export const TargetTypeRestriction = type('"COLLECTION" | "EDITION" | "ISSUE" | "VOLUME" | "OPUS" | "SEASON" | "SEQUEL" | "ALBUM" | "OPERA" | "CONCERT" | "MOVIE" | "EPISODE" | "PART" | "SESSION" | "TRACK" | "SONG" | "CHAPTER" | "SUBTRACK" | "MOVEMENT" | "SCENE" | "SHOT"');
|
||||||
'"COLLECTION" | "EDITION" | "ISSUE" | "VOLUME" | "OPUS" | "SEASON" | "SEQUEL" | "ALBUM" | "OPERA" | "CONCERT" | "MOVIE" | "EPISODE" | "PART" | "SESSION" | "TRACK" | "SONG" | "CHAPTER" | "SUBTRACK" | "MOVEMENT" | "SCENE" | "SHOT"'
|
|
||||||
);
|
|
||||||
export type TargetTypeRestrictionType = typeof TargetTypeRestriction.infer;
|
export type TargetTypeRestrictionType = typeof TargetTypeRestriction.infer;
|
||||||
|
|
||||||
export const TargetsSchema = type({
|
export const TargetsSchema = type({
|
||||||
@ -977,12 +946,13 @@ export type TargetsType = typeof TargetsSchema.infer;
|
|||||||
|
|
||||||
export const TagSchema = type({
|
export const TagSchema = type({
|
||||||
Targets: TargetsSchema,
|
Targets: TargetsSchema,
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TagType = typeof TagSchema.infer;
|
export type TagType = typeof TagSchema.infer;
|
||||||
|
|
||||||
export const TagsSchema = type({
|
export const TagsSchema = type({
|
||||||
Tag: TagSchema.array(),
|
Tag: TagSchema.array().atLeastLength(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type TagsType = typeof TagsSchema.infer;
|
export type TagsType = typeof TagsSchema.infer;
|
||||||
@ -1037,5 +1007,5 @@ export const IdMultiSet = new Set([
|
|||||||
EbmlTagIdEnum.Tag,
|
EbmlTagIdEnum.Tag,
|
||||||
EbmlTagIdEnum.SeekHead,
|
EbmlTagIdEnum.SeekHead,
|
||||||
EbmlTagIdEnum.Cluster,
|
EbmlTagIdEnum.Cluster,
|
||||||
EbmlTagIdEnum.Tags,
|
EbmlTagIdEnum.Tags
|
||||||
]);
|
])
|
@ -2,11 +2,7 @@ import type { Type } from 'arktype';
|
|||||||
import { EbmlElementType, EbmlTagIdEnum, type EbmlTagType } from 'konoebml';
|
import { EbmlElementType, EbmlTagIdEnum, type EbmlTagType } from 'konoebml';
|
||||||
import { IdMultiSet } from './schema';
|
import { IdMultiSet } from './schema';
|
||||||
|
|
||||||
export type InferType<T> = T extends Type<infer U> ? U : never;
|
export type InferType<T extends Type<any>> = T['infer'];
|
||||||
|
|
||||||
export const SEEK_ID_KAX_INFO = new Uint8Array([0x15, 0x49, 0xa9, 0x66]);
|
|
||||||
export const SEEK_ID_KAX_TRACKS = new Uint8Array([0x16, 0x54, 0xae, 0x6b]);
|
|
||||||
export const SEEK_ID_KAX_CUES = new Uint8Array([0x1c, 0x53, 0xbb, 0x6b]);
|
|
||||||
|
|
||||||
export type PredicateIdExtract<T, K> = Extract<T, { id: K }>;
|
export type PredicateIdExtract<T, K> = Extract<T, { id: K }>;
|
||||||
|
|
||||||
@ -31,13 +27,13 @@ export function isTagPos<
|
|||||||
pos === '*' || pos === tag.position;
|
pos === '*' || pos === tag.position;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function convertEbmlTagToModelShape(tag: EbmlTagType) {
|
export function convertEbmlTagToComponent (tag: EbmlTagType) {
|
||||||
if (tag.type === EbmlElementType.Master) {
|
if (tag.type === EbmlElementType.Master) {
|
||||||
const obj: Record<string, any> = {};
|
const obj: Record<string, any> = {};
|
||||||
const children = tag.children;
|
const children = tag.children;
|
||||||
for (const c of children) {
|
for (const c of children) {
|
||||||
const name = EbmlTagIdEnum[c.id];
|
const name = EbmlTagIdEnum[c.id];
|
||||||
const converted = convertEbmlTagToModelShape(c);
|
const converted = convertEbmlTagToComponent(c);
|
||||||
if (IdMultiSet.has(c.id)) {
|
if (IdMultiSet.has(c.id)) {
|
||||||
if (obj[name]) {
|
if (obj[name]) {
|
||||||
obj[name].push(converted);
|
obj[name].push(converted);
|
||||||
@ -48,6 +44,7 @@ export function convertEbmlTagToModelShape(tag: EbmlTagType) {
|
|||||||
obj[name] = converted;
|
obj[name] = converted;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return obj;
|
||||||
}
|
}
|
||||||
if (tag.id === EbmlTagIdEnum.SimpleBlock || tag.id === EbmlTagIdEnum.Block) {
|
if (tag.id === EbmlTagIdEnum.SimpleBlock || tag.id === EbmlTagIdEnum.Block) {
|
||||||
return tag;
|
return tag;
|
||||||
|
@ -390,6 +390,9 @@ function generateMkvSchemaHierarchy(elements_: EbmlElementType[]) {
|
|||||||
: meta.primitive(v.name);
|
: meta.primitive(v.name);
|
||||||
if (v.maxOccurs !== 1) {
|
if (v.maxOccurs !== 1) {
|
||||||
expr = `${expr}.array()`;
|
expr = `${expr}.array()`;
|
||||||
|
if (v.maxOccurs !== 1 && v.minOccurs === 1 && !v.default) {
|
||||||
|
expr = `${expr}.atLeastLength(1)`
|
||||||
|
}
|
||||||
idMulti.add(v.name);
|
idMulti.add(v.name);
|
||||||
}
|
}
|
||||||
if (v.default) {
|
if (v.default) {
|
||||||
|
Loading…
Reference in New Issue
Block a user