dasha 4.0.3 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,6 +42,7 @@ async function saveVideo() {
42
42
  });
43
43
 
44
44
  const bestVideoTrack = videoTracks[0];
45
+ console.log('Dynamic range:', await bestVideoTrack.getDynamicRange()); // sdr
45
46
 
46
47
  const segments = await bestVideoTrack.getSegments();
47
48
 
@@ -93,6 +94,43 @@ async function saveDashVideo() {
93
94
  }
94
95
  ```
95
96
 
97
+ ### Adding external subtitle tracks
98
+
99
+ `addSubtitleTrack()` is useful when subtitle URLs are provided separately from the HLS/DASH manifest. Added subtitles become part of the same `Input`, so they can be queried, filtered and downloaded through the regular subtitle track API.
100
+
101
+ ```ts
102
+ import { DASH_FORMATS, Input, UrlSource } from 'dasha';
103
+
104
+ async function getEnglishSubtitles() {
105
+ const input = new Input({
106
+ source: new UrlSource('https://example.com/manifest.mpd'),
107
+ formats: DASH_FORMATS,
108
+ });
109
+
110
+ const primaryVideoTrack = await input.getPrimaryVideoTrack();
111
+ if (!primaryVideoTrack) {
112
+ throw new Error('No video tracks found');
113
+ }
114
+
115
+ input.addSubtitleTrack(new UrlSource('https://cdn.example.com/subtitles/en.vtt'), {
116
+ languageCode: 'en',
117
+ name: 'English',
118
+ pairWith: primaryVideoTrack,
119
+ });
120
+
121
+ const englishSubtitleTracks = await input.getSubtitleTracks({
122
+ filter: async (track) => (await track.getLanguageCode()) === 'en',
123
+ });
124
+
125
+ const englishSubtitleTrack = englishSubtitleTracks[0];
126
+ if (!englishSubtitleTrack) {
127
+ return [];
128
+ }
129
+
130
+ return await englishSubtitleTrack.getSegments();
131
+ }
132
+ ```
133
+
96
134
  ### Mediabunny with DASH support
97
135
 
98
136
  > Only reading is supported
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as _$mediabunny from "mediabunny";
2
- import { AudioCodec, DurationMetadataRequestOptions, EncodedPacket, FilePathSource, HLS_FORMATS, Input as Input$1, InputAudioTrack as InputAudioTrack$1, InputFormat, InputOptions, InputTrack as InputTrack$2, InputTrackQuery, InputTrackQuery as InputTrackQuery$1, InputVideoTrack as InputVideoTrack$1, MediaCodec, MetadataTags, PacketRetrievalOptions, Source, TrackDisposition, UrlSource, VideoCodec, asc, desc, prefer } from "mediabunny";
2
+ import { AudioCodec as AudioCodec$1, DurationMetadataRequestOptions, EncodedPacket, FilePathSource, HLS, HLS_FORMATS, Input as Input$1, InputAudioTrack as InputAudioTrack$1, InputFormat, InputOptions, InputTrack as InputTrack$2, InputTrackQuery, InputTrackQuery as InputTrackQuery$1, InputVideoTrack as InputVideoTrack$1, MP3, MP4, MaybePromise, MediaCodec as MediaCodec$1, MetadataTags, PacketRetrievalOptions, PathedSource, Source, SourceRef, SubtitleCodec as SubtitleCodec$1, TrackDisposition, UrlSource, VideoCodec as VideoCodec$1, asc, desc, prefer } from "mediabunny";
3
3
  import { Element } from "@xmldom/xmldom";
4
4
 
5
5
  //#region src/mediabunny.d.ts
@@ -46,60 +46,47 @@ type InputTrackWithBacking = InputTrack & {
46
46
  };
47
47
  //#endregion
48
48
  //#region src/codec.d.ts
49
- /**
50
- * List of known video codecs, ordered by encoding preference.
51
- * @group Codecs
52
- * @public
53
- */
54
- declare const VIDEO_CODECS: readonly ["avc", "hevc", "vp8", "vp9", "av1", "vc1"];
55
- /**
56
- * List of known video dynamic ranges.
57
- * @group Codecs
58
- * @public
59
- */
60
- declare const VIDEO_DYNAMIC_RANGES: readonly ["sdr", "hlg", "hdr10", "hdr10+", "dv"];
61
- /**
62
- * List of known audio codecs, ordered by encoding preference.
63
- * @group Codecs
64
- * @public
65
- */
66
- declare const AUDIO_CODECS: readonly ["aac", "opus", "mp3", "vorbis", "flac", "alac", "ac3", "eac3", "dts"];
67
- /**
68
- * List of known subtitle codecs, ordered by encoding preference.
69
- * @group Codecs
70
- * @public
71
- */
72
- declare const SUBTITLE_CODECS: readonly ["srt", "vtt", "ttml", "dfxp", "ssa", "ass", "stpp", "wvtt"];
73
49
  /**
74
50
  * Union type of known video codecs.
75
51
  * @group Codecs
76
52
  * @public
77
53
  */
78
- type VideoCodec$1 = (typeof VIDEO_CODECS)[number];
54
+ type VideoCodec = VideoCodec$1 | 'vc1';
79
55
  /**
80
56
  * Union type of known video dynamic ranges.
57
+ *
58
+ * `sdr`: Standard Dynamic Range
59
+ *
60
+ * `hlg`: High-Luminance Gamma
61
+ *
62
+ * `hdr10`: High-Dynamic Range 10
63
+ *
64
+ * `hdr10+`: High-Dynamic Range 10+
65
+ *
66
+ * `dv`: Dolby Vision
67
+ *
81
68
  * @group Codecs
82
69
  * @public
83
70
  */
84
- type VideoDynamicRange = (typeof VIDEO_DYNAMIC_RANGES)[number];
71
+ type VideoDynamicRange = 'sdr' | 'hlg' | 'hdr10' | 'hdr10+' | 'dv';
85
72
  /**
86
73
  * Union type of known audio codecs.
87
74
  * @group Codecs
88
75
  * @public
89
76
  */
90
- type AudioCodec$1 = (typeof AUDIO_CODECS)[number];
77
+ type AudioCodec = AudioCodec$1 | 'dts' | 'alac';
91
78
  /**
92
79
  * Union type of known subtitle codecs.
93
80
  * @group Codecs
94
81
  * @public
95
82
  */
96
- type SubtitleCodec = (typeof SUBTITLE_CODECS)[number];
83
+ type SubtitleCodec = SubtitleCodec$1 | 'srt' | 'ttml' | 'dfxp' | 'ssa' | 'ass' | 'stpp';
97
84
  /**
98
85
  * Union type of known media codecs.
99
86
  * @group Codecs
100
87
  * @public
101
88
  */
102
- type MediaCodec$1 = VideoCodec$1 | AudioCodec$1 | SubtitleCodec;
89
+ type MediaCodec = VideoCodec | AudioCodec | SubtitleCodec;
103
90
  //#endregion
104
91
  //#region src/role-type.d.ts
105
92
  declare const ROLE_TYPE: {
@@ -148,7 +135,7 @@ type DashParsedSegment = {
148
135
  };
149
136
  type DashTrackCommon = {
150
137
  type: DashTrackType;
151
- codec?: MediaCodec$1;
138
+ codec?: MediaCodec;
152
139
  codecString: string | null;
153
140
  languageCode?: string;
154
141
  peakBitrate: number | null;
@@ -171,6 +158,7 @@ type DashParsedVideoTrack = DashTrackCommon & {
171
158
  width?: number;
172
159
  height?: number;
173
160
  frameRate?: number;
161
+ colorSpace?: VideoColorSpaceInit;
174
162
  dynamicRange?: VideoDynamicRange;
175
163
  };
176
164
  type DashParsedAudioTrack = DashTrackCommon & {
@@ -385,7 +373,7 @@ declare abstract class DashTrackBackingBase {
385
373
  delegate<T>(fn: (track: any) => T | Promise<T>): Promise<T>;
386
374
  getId(): number;
387
375
  getNumber(): number;
388
- getCodec(): MediaCodec | null;
376
+ getCodec(): MediaCodec$1 | null;
389
377
  getInternalCodecId(): null;
390
378
  getName(): string | null;
391
379
  getLanguageCode(): string;
@@ -412,7 +400,7 @@ declare class DashInputVideoTrackBacking extends DashTrackBackingBase {
412
400
  internalTrack: InternalVideoTrack;
413
401
  constructor(internalTrack: InternalVideoTrack);
414
402
  getType(): "video";
415
- getCodec(): VideoCodec | null;
403
+ getCodec(): VideoCodec$1 | null;
416
404
  getCodedWidth(): number | Promise<any>;
417
405
  getCodedHeight(): number | Promise<any>;
418
406
  getSquarePixelWidth(): number | Promise<any>;
@@ -427,7 +415,7 @@ declare class DashInputAudioTrackBacking extends DashTrackBackingBase {
427
415
  internalTrack: InternalAudioTrack;
428
416
  constructor(internalTrack: InternalAudioTrack);
429
417
  getType(): "audio";
430
- getCodec(): AudioCodec | null;
418
+ getCodec(): AudioCodec$1 | null;
431
419
  getNumberOfChannels(): number | Promise<any>;
432
420
  getSampleRate(): number | Promise<any>;
433
421
  }
@@ -446,9 +434,121 @@ declare class DashInputFormat extends InputFormat {
446
434
  declare const DASH: DashInputFormat;
447
435
  declare const DASH_FORMATS: InputFormat[];
448
436
  //#endregion
437
+ //#region src/hls/hls-subtitles.d.ts
438
+ type SourceWithRootPath = {
439
+ rootPath: string;
440
+ _options?: {
441
+ requestInit?: RequestInit;
442
+ };
443
+ _url?: string | URL | Request;
444
+ };
445
+ type HlsSubtitleMediaTag = {
446
+ autoselect: boolean;
447
+ codec: SubtitleCodec;
448
+ codecString: string;
449
+ default: boolean;
450
+ forced: boolean;
451
+ groupId: string;
452
+ hearingImpaired: boolean;
453
+ languageCode: string;
454
+ name: string | null;
455
+ uri: string;
456
+ };
457
+ declare class HlsSubtitlePlaylist implements HlsSegmentedInput {
458
+ #private;
459
+ segments: HlsSegment[];
460
+ constructor(source: SourceWithRootPath, playlistPath: string);
461
+ runUpdateSegments(): Promise<void>;
462
+ getDurationFromMetadata(_options: DurationMetadataRequestOptions): Promise<number | null>;
463
+ getLiveRefreshInterval(): Promise<number | null>;
464
+ isRelativeToUnixEpoch(): Promise<boolean>;
465
+ }
466
+ declare class ExternalSubtitleSegmentedInput implements HlsSegmentedInput {
467
+ #private;
468
+ segments: HlsSegment[];
469
+ constructor(source: SourceWithRootPath, rootPath: string);
470
+ runUpdateSegments(): Promise<void>;
471
+ getDurationFromMetadata(options: DurationMetadataRequestOptions): Promise<number | null>;
472
+ getLiveRefreshInterval(): Promise<number | null>;
473
+ isRelativeToUnixEpoch(): Promise<boolean>;
474
+ }
475
+ declare class HlsSubtitleTrackBacking {
476
+ #private;
477
+ constructor(params: {
478
+ id: number;
479
+ number: number;
480
+ pairingMask: bigint;
481
+ source: SourceWithRootPath;
482
+ track: HlsSubtitleMediaTag;
483
+ });
484
+ getType(): "subtitle";
485
+ getId(): number;
486
+ getNumber(): number;
487
+ getCodec(): never;
488
+ getInternalCodecId(): null;
489
+ getName(): string | null;
490
+ getLanguageCode(): string;
491
+ getTimeResolution(): number;
492
+ isRelativeToUnixEpoch(): Promise<boolean>;
493
+ getDisposition(): TrackDisposition;
494
+ getPairingMask(): bigint;
495
+ getBitrate(): null;
496
+ getAverageBitrate(): null;
497
+ getDurationFromMetadata(options: DurationMetadataRequestOptions): Promise<number | null>;
498
+ getLiveRefreshInterval(): Promise<number | null>;
499
+ getHasOnlyKeyPackets(): boolean;
500
+ getDecoderConfig(): Promise<null>;
501
+ getMetadataCodecParameterString(): string;
502
+ getFirstPacket(_options: unknown): Promise<EncodedPacket | null>;
503
+ getPacket(_timestamp: number, _options: unknown): Promise<EncodedPacket | null>;
504
+ getNextPacket(_packet: EncodedPacket, _options: unknown): Promise<EncodedPacket | null>;
505
+ getKeyPacket(_timestamp: number, _options: unknown): Promise<EncodedPacket | null>;
506
+ getNextKeyPacket(_packet: EncodedPacket, _options: unknown): Promise<EncodedPacket | null>;
507
+ getSegmentedInput(): HlsSubtitlePlaylist;
508
+ }
509
+ declare class ExternalSubtitleTrackBacking {
510
+ #private;
511
+ constructor(params: {
512
+ id: number;
513
+ number: number;
514
+ pairingMask: bigint;
515
+ source: SourceWithRootPath;
516
+ codec?: SubtitleCodec | null;
517
+ codecString?: string | null;
518
+ languageCode?: string;
519
+ name?: string | null;
520
+ disposition?: Partial<TrackDisposition>;
521
+ });
522
+ getType(): "subtitle";
523
+ getId(): number;
524
+ getNumber(): number;
525
+ getCodec(): Promise<never>;
526
+ getInternalCodecId(): null;
527
+ getName(): string | null;
528
+ getLanguageCode(): string;
529
+ getTimeResolution(): number;
530
+ isRelativeToUnixEpoch(): Promise<boolean>;
531
+ getDisposition(): TrackDisposition;
532
+ getPairingMask(): bigint;
533
+ getBitrate(): null;
534
+ getAverageBitrate(): null;
535
+ getDurationFromMetadata(options: DurationMetadataRequestOptions): Promise<number | null>;
536
+ getLiveRefreshInterval(): Promise<number | null>;
537
+ getHasOnlyKeyPackets(): boolean;
538
+ getDecoderConfig(): Promise<null>;
539
+ getMetadataCodecParameterString(): Promise<string | null>;
540
+ getFirstPacket(_options: unknown): Promise<EncodedPacket | null>;
541
+ getPacket(_timestamp: number, _options: unknown): Promise<EncodedPacket | null>;
542
+ getNextPacket(_packet: EncodedPacket, _options: unknown): Promise<EncodedPacket | null>;
543
+ getKeyPacket(_timestamp: number, _options: unknown): Promise<EncodedPacket | null>;
544
+ getNextKeyPacket(_packet: EncodedPacket, _options: unknown): Promise<EncodedPacket | null>;
545
+ getSegmentedInput(): ExternalSubtitleSegmentedInput;
546
+ }
547
+ //#endregion
449
548
  //#region src/mediabunny-input.d.ts
450
549
  declare module 'mediabunny' {
451
550
  interface Input<S extends Source = Source> {
551
+ _getDemuxer(): Promise<unknown>;
452
552
  _getTrackBackings(): Promise<unknown[]>;
453
553
  _wrapBackingAsTrack(backing: unknown): InputTrack$2;
454
554
  }
@@ -457,19 +557,62 @@ type SegmentAccessMethods = {
457
557
  getSegmentedInput(): HlsSegmentedInput | DashSegmentedInput;
458
558
  getSegments(): Promise<(HlsSegment | DashSegment)[]>;
459
559
  };
460
- type MediabunnyTrackWithSegments = InputTrack$2 & SegmentAccessMethods;
461
- type MediabunnyVideoTrackWithSegments = InputVideoTrack$1 & SegmentAccessMethods;
462
- type MediabunnyAudioTrackWithSegments = InputAudioTrack$1 & SegmentAccessMethods;
463
- type TrackBacking = Parameters<Input$1<Source>['_wrapBackingAsTrack']>[0];
560
+ type VideoDynamicRangeMethods = {
561
+ getDynamicRange(): Promise<VideoDynamicRange>;
562
+ };
563
+ type MediabunnySubtitleTrackLike = InputTrack$2 & {
564
+ type: 'subtitle';
565
+ };
566
+ type InputTrack$1 = InputTrack$2 & SegmentAccessMethods;
567
+ type InputVideoTrack = InputVideoTrack$1 & SegmentAccessMethods & VideoDynamicRangeMethods;
568
+ type InputAudioTrack = InputAudioTrack$1 & SegmentAccessMethods;
569
+ type InputSubtitleTrack = MediabunnySubtitleTrackLike & SegmentAccessMethods;
570
+ type InputSubtitleSource = PathedSource | SourceRef<PathedSource>;
571
+ type InputSubtitleTrackMetadata = {
572
+ codec?: SubtitleCodec | null;
573
+ codecString?: string | null;
574
+ disposition?: Partial<TrackDisposition>;
575
+ languageCode?: string;
576
+ name?: string | null;
577
+ pairWith?: InputVideoTrack | Iterable<InputVideoTrack>;
578
+ };
579
+ type SegmentableBacking = {
580
+ getId(): number;
581
+ getNumber(): number;
582
+ getType(): string;
583
+ getCodec(): MediaCodec$1 | null | Promise<MediaCodec$1 | null>;
584
+ getInternalCodecId?(): string | number | Uint8Array | null | Promise<string | number | Uint8Array | null>;
585
+ getName?(): string | null | Promise<string | null>;
586
+ getLanguageCode?(): string | Promise<string>;
587
+ getTimeResolution?(): number | Promise<number>;
588
+ isRelativeToUnixEpoch?(): boolean | Promise<boolean>;
589
+ getDisposition?(): unknown | Promise<unknown>;
590
+ getPairingMask?(): bigint;
591
+ getBitrate?(): number | null | Promise<number | null>;
592
+ getAverageBitrate?(): number | null | Promise<number | null>;
593
+ getDurationFromMetadata?(options: unknown): Promise<number | null>;
594
+ getLiveRefreshInterval?(): Promise<number | null>;
595
+ getDecoderConfig?(): Promise<VideoDecoderConfig | AudioDecoderConfig | null>;
596
+ getMetadataCodecParameterString?(): string | null | Promise<string | null>;
597
+ getSegmentedInput?(): HlsSegmentedInput | DashSegmentedInput;
598
+ };
599
+ type NativeTrackBacking = SegmentableBacking;
600
+ type TrackBacking = NativeTrackBacking | SegmentableBacking;
601
+ declare const BACKING_TYPE_SUBTITLE = "subtitle";
602
+ declare const BACKING_TYPE_AUDIO = "audio";
603
+ declare const BACKING_TYPE_VIDEO = "video";
464
604
  declare const preserveSubtitleBackingsOnInput: (input: Input$1) => Input$1<Source>;
465
605
  declare class SegmentedMediabunnyInput<S extends Source = Source> extends Input$1<S> {
466
606
  #private;
467
- _wrapBackingAsTrack(backing: TrackBacking): MediabunnyTrackWithSegments;
468
- getTracks(query?: InputTrackQuery$1<MediabunnyTrackWithSegments>): Promise<MediabunnyTrackWithSegments[]>;
469
- getVideoTracks(query?: InputTrackQuery$1<MediabunnyVideoTrackWithSegments>): Promise<MediabunnyVideoTrackWithSegments[]>;
470
- getAudioTracks(query?: InputTrackQuery$1<MediabunnyAudioTrackWithSegments>): Promise<MediabunnyAudioTrackWithSegments[]>;
471
- getPrimaryVideoTrack(query?: InputTrackQuery$1<MediabunnyVideoTrackWithSegments>): Promise<MediabunnyVideoTrackWithSegments | null>;
472
- getPrimaryAudioTrack(query?: InputTrackQuery$1<MediabunnyAudioTrackWithSegments>): Promise<MediabunnyAudioTrackWithSegments | null>;
607
+ _wrapBackingAsTrack(backing: TrackBacking): InputTrack$1;
608
+ _getSyntheticTrackBackings(type?: typeof BACKING_TYPE_VIDEO | typeof BACKING_TYPE_AUDIO | typeof BACKING_TYPE_SUBTITLE): Promise<(ExternalSubtitleTrackBacking | HlsSubtitleTrackBacking)[]>;
609
+ getTracks(query?: InputTrackQuery$1<InputTrack$1>): Promise<InputTrack$1[]>;
610
+ getVideoTracks(query?: InputTrackQuery$1<InputVideoTrack>): Promise<InputVideoTrack[]>;
611
+ getAudioTracks(query?: InputTrackQuery$1<InputAudioTrack>): Promise<InputAudioTrack[]>;
612
+ getSubtitleTracks(query?: InputTrackQuery$1<InputSubtitleTrack>): Promise<InputSubtitleTrack[]>;
613
+ getPrimaryVideoTrack(query?: InputTrackQuery$1<InputVideoTrack>): Promise<InputVideoTrack | null>;
614
+ getPrimaryAudioTrack(query?: InputTrackQuery$1<InputAudioTrack>): Promise<InputAudioTrack | null>;
615
+ addSubtitleTrack(source: InputSubtitleSource, metadata?: InputSubtitleTrackMetadata): InputSubtitleTrack;
473
616
  }
474
617
  //#endregion
475
618
  //#region src/index.d.ts
@@ -478,14 +621,12 @@ type DashaInputOptions<S extends Source = Source> = Omit<InputOptions<S>, 'forma
478
621
  };
479
622
  type InputSegment = HlsSegment | DashSegment;
480
623
  type InputSegmentedInput = HlsSegmentedInput | DashSegmentedInput;
481
- type InputTrack$1 = MediabunnyTrackWithSegments;
482
- type InputVideoTrack = MediabunnyVideoTrackWithSegments;
483
- type InputAudioTrack = MediabunnyAudioTrackWithSegments;
484
624
  declare class Input<S extends Source = Source> extends SegmentedMediabunnyInput<S> {
485
625
  constructor(options: DashaInputOptions<S>);
486
626
  }
487
627
  declare const isInput: (value: unknown) => value is Input;
488
628
  declare const getSegmentedInput: (track: InputTrack$1) => InputSegmentedInput;
489
629
  declare const getSegments: (track: InputTrack$1) => Promise<InputSegment[]>;
630
+ declare const ALL_FORMATS: InputFormat[];
490
631
  //#endregion
491
- export { DASH, DASH_FORMATS, type DashSegment, type DashSegmentedInput, FilePathSource, HLS_FORMATS, type HlsSegment, type HlsSegmentedInput, Input, InputAudioTrack, InputSegment, InputSegmentedInput, InputTrack$1 as InputTrack, type InputTrackQuery, type InputTrackWithBacking, InputVideoTrack, UrlSource, asc, desc, getSegmentedInput, getSegments, isInput, prefer, preserveSubtitleBackingsOnInput };
632
+ export { ALL_FORMATS, type AudioCodec, DASH, DASH_FORMATS, type DashSegment, type DashSegmentedInput, FilePathSource, HLS, HLS_FORMATS, type HlsSegment, type HlsSegmentedInput, Input, type InputAudioTrack, InputSegment, InputSegmentedInput, type InputSubtitleSource, type InputSubtitleTrack, type InputSubtitleTrackMetadata, type InputTrack$1 as InputTrack, type InputTrackQuery, type InputTrackWithBacking, type InputVideoTrack, MP3, MP4, type MaybePromise, type MediaCodec, type SubtitleCodec, UrlSource, type VideoCodec, type VideoDynamicRange, asc, desc, getSegmentedInput, getSegments, isInput, prefer, preserveSubtitleBackingsOnInput };