feat: add codegen and refactor mkv models

This commit is contained in:
master 2025-03-22 03:11:40 +08:00
parent f921819d2a
commit 0b681d4fd1
5 changed files with 345 additions and 274 deletions

View File

@ -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;
constructor(startNode: EbmlSegmentTagType) {
this.startTag = startNode;
this.cue = new CueSystem(this);
this.cluster = new ClusterSystem(this);
this.seek = new SeekSystem(this);
this.info = new InfoSystem(this);
this.track = new TrackSystem(this);
}
get dataStartOffset() {
return this.startTag.startOffset + this.startTag.headerLength;
}
get startOffset () {
return this.startTag.startOffset;
}
completeHeads () {
const infoTag = this.seek.seekTagBySeekId(SEEK_ID_KAX_INFO);
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);
}
return this;
}
scanHead (tag: EbmlTagType) {
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 EbmlSegment { export class SegmentComponentSystemTrait<E extends EbmlMasterTagType, S extends Type<any>> {
startNode: EbmlSegmentTagType; segment: SegmentSystem;
seekHeadNode?: EbmlSeekHeadTagType;
seekEntries: EbmlSeekEntry[];
tracksNode?: EbmlTracksTagType;
infoNode?: EbmlInfoTagType;
cuesNode?: EbmlCuesTagType;
metaBuffer: EbmlTagType[] = [];
metaOffsets: Map<number, EbmlTagType> = new Map();
constructor(startNode: EbmlSegmentTagType) { get schema(): S {
this.startNode = startNode; throw new Error("unimplemented!")
this.seekEntries = [];
this.metaBuffer = [];
} }
get dataOffset() { constructor(segment: SegmentSystem) {
return this.startNode.startOffset + this.startNode.headerLength; this.segment = segment;
} }
private addSeekHead(node: EbmlSeekHeadTagType) { componentFromTag(tag: E): InferType<S> {
this.seekHeadNode = node; const extracted = convertEbmlTagToComponent(tag);
this.seekEntries = this.seekHeadNode.children const result = this.schema(extracted);
.filter(isTagIdPos(EbmlTagIdEnum.Seek, EbmlTagPosition.End)) if (result instanceof ArkErrors) {
.map((c) => { const errors = result;
const seekId = c.children.find( console.error('Parse component from tag error:', tag.toDebugRecord(), errors.flatProblemsByPath)
(item) => item.id === EbmlTagIdEnum.SeekID throw errors;
)?.data; }
const seekPosition = c.children.find( return result as InferType<S>
(item) => item.id === EbmlTagIdEnum.SeekPosition }
)?.data as number; }
if (seekId && seekPosition) {
return { export class SeekSystem extends SegmentComponentSystemTrait<EbmlSeekHeadTagType, typeof SeekHeadSchema> {
seekId, override get schema() {
seekPosition, return SeekHeadSchema;
};
}
return null;
})
.filter((c): c is EbmlSeekEntry => !!c);
} }
findSeekPositionBySeekId(seekId: Uint8Array): number | undefined { seekHeads: SeekHeadType[] = [];
return this.seekEntries.find((c) => isEqual(c.seekId, seekId)) offsetToTagMemo: Map<number, EbmlTagType> = new Map();
?.seekPosition;
memoTag (tag: EbmlTagType) {
this.offsetToTagMemo.set(tag.startOffset, tag);
} }
findLocalNodeBySeekId(seekId: Uint8Array): EbmlTagType | undefined { addSeekHeadTag (tag: EbmlSeekHeadTagType) {
return this.findLocalNodeBySeekPosition( const seekHead = this.componentFromTag(tag);
this.findSeekPositionBySeekId(seekId) this.seekHeads.push(seekHead);
); return seekHead;
} }
findLocalNodeBySeekPosition( offsetFromSeekPosition (position: number): number {
seekPosition: number | undefined 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;
}
} }

View File

@ -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)))

View File

@ -1,5 +1,5 @@
import { type, match } from 'arktype'; import { type, match } from 'arktype';
import { EbmlTagIdEnum, EbmlSimpleBlockTag, EbmlBlockTag } from 'konoebml'; import { EbmlTagIdEnum, EbmlSimpleBlockTag ,EbmlBlockTag } from 'konoebml';
export const BinarySchema = type.instanceOf(Uint8Array); export const BinarySchema = type.instanceOf(Uint8Array);
export const SimpleBlockSchema = type.instanceOf(EbmlSimpleBlockTag); export const SimpleBlockSchema = type.instanceOf(EbmlSimpleBlockTag);
@ -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
]); ])

View File

@ -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;

View File

@ -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) {