avbridge 1.0.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/CHANGELOG.md +120 -0
- package/LICENSE +21 -0
- package/README.md +415 -0
- package/dist/avi-M5B4SHRM.cjs +164 -0
- package/dist/avi-M5B4SHRM.cjs.map +1 -0
- package/dist/avi-POCGZ4JX.js +162 -0
- package/dist/avi-POCGZ4JX.js.map +1 -0
- package/dist/chunk-5ISVAODK.js +80 -0
- package/dist/chunk-5ISVAODK.js.map +1 -0
- package/dist/chunk-F7YS2XOA.cjs +2966 -0
- package/dist/chunk-F7YS2XOA.cjs.map +1 -0
- package/dist/chunk-FKM7QBZU.js +2957 -0
- package/dist/chunk-FKM7QBZU.js.map +1 -0
- package/dist/chunk-J5MCMN3S.js +27 -0
- package/dist/chunk-J5MCMN3S.js.map +1 -0
- package/dist/chunk-L4NPOJ36.cjs +180 -0
- package/dist/chunk-L4NPOJ36.cjs.map +1 -0
- package/dist/chunk-NZU7W256.cjs +29 -0
- package/dist/chunk-NZU7W256.cjs.map +1 -0
- package/dist/chunk-PQTZS7OA.js +147 -0
- package/dist/chunk-PQTZS7OA.js.map +1 -0
- package/dist/chunk-WD2ZNQA7.js +177 -0
- package/dist/chunk-WD2ZNQA7.js.map +1 -0
- package/dist/chunk-Y5FYF5KG.cjs +153 -0
- package/dist/chunk-Y5FYF5KG.cjs.map +1 -0
- package/dist/chunk-Z2FJ5TJC.cjs +82 -0
- package/dist/chunk-Z2FJ5TJC.cjs.map +1 -0
- package/dist/element.cjs +433 -0
- package/dist/element.cjs.map +1 -0
- package/dist/element.d.cts +158 -0
- package/dist/element.d.ts +158 -0
- package/dist/element.js +431 -0
- package/dist/element.js.map +1 -0
- package/dist/index.cjs +576 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +80 -0
- package/dist/index.d.ts +80 -0
- package/dist/index.js +554 -0
- package/dist/index.js.map +1 -0
- package/dist/libav-http-reader-FPYDBMYK.cjs +16 -0
- package/dist/libav-http-reader-FPYDBMYK.cjs.map +1 -0
- package/dist/libav-http-reader-NQJVY273.js +3 -0
- package/dist/libav-http-reader-NQJVY273.js.map +1 -0
- package/dist/libav-import-2JURFHEW.js +8 -0
- package/dist/libav-import-2JURFHEW.js.map +1 -0
- package/dist/libav-import-GST2AMPL.cjs +30 -0
- package/dist/libav-import-GST2AMPL.cjs.map +1 -0
- package/dist/libav-loader-KA2MAWLM.js +3 -0
- package/dist/libav-loader-KA2MAWLM.js.map +1 -0
- package/dist/libav-loader-ZHOERPHW.cjs +12 -0
- package/dist/libav-loader-ZHOERPHW.cjs.map +1 -0
- package/dist/player-BBwbCkdL.d.cts +365 -0
- package/dist/player-BBwbCkdL.d.ts +365 -0
- package/dist/source-SC6ZEQYR.cjs +28 -0
- package/dist/source-SC6ZEQYR.cjs.map +1 -0
- package/dist/source-ZFS4H7J3.js +3 -0
- package/dist/source-ZFS4H7J3.js.map +1 -0
- package/dist/variant-routing-GOHB2RZN.cjs +12 -0
- package/dist/variant-routing-GOHB2RZN.cjs.map +1 -0
- package/dist/variant-routing-JOBWXYKD.js +3 -0
- package/dist/variant-routing-JOBWXYKD.js.map +1 -0
- package/package.json +95 -0
- package/src/classify/index.ts +1 -0
- package/src/classify/rules.ts +214 -0
- package/src/convert/index.ts +2 -0
- package/src/convert/remux.ts +522 -0
- package/src/convert/transcode.ts +329 -0
- package/src/diagnostics.ts +99 -0
- package/src/element/avbridge-player.ts +576 -0
- package/src/element.ts +19 -0
- package/src/events.ts +71 -0
- package/src/index.ts +42 -0
- package/src/libav-stubs.d.ts +24 -0
- package/src/player.ts +455 -0
- package/src/plugins/builtin.ts +37 -0
- package/src/plugins/registry.ts +32 -0
- package/src/probe/avi.ts +242 -0
- package/src/probe/index.ts +59 -0
- package/src/probe/mediabunny.ts +194 -0
- package/src/strategies/fallback/audio-output.ts +293 -0
- package/src/strategies/fallback/clock.ts +7 -0
- package/src/strategies/fallback/decoder.ts +660 -0
- package/src/strategies/fallback/index.ts +170 -0
- package/src/strategies/fallback/libav-import.ts +27 -0
- package/src/strategies/fallback/libav-loader.ts +190 -0
- package/src/strategies/fallback/variant-routing.ts +43 -0
- package/src/strategies/fallback/video-renderer.ts +216 -0
- package/src/strategies/hybrid/decoder.ts +641 -0
- package/src/strategies/hybrid/index.ts +139 -0
- package/src/strategies/native.ts +107 -0
- package/src/strategies/remux/annexb.ts +112 -0
- package/src/strategies/remux/index.ts +79 -0
- package/src/strategies/remux/mse.ts +234 -0
- package/src/strategies/remux/pipeline.ts +254 -0
- package/src/subtitles/index.ts +91 -0
- package/src/subtitles/render.ts +62 -0
- package/src/subtitles/srt.ts +62 -0
- package/src/subtitles/vtt.ts +5 -0
- package/src/types-shim.d.ts +3 -0
- package/src/types.ts +360 -0
- package/src/util/codec-strings.ts +86 -0
- package/src/util/libav-http-reader.ts +315 -0
- package/src/util/source.ts +274 -0
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core types shared across avbridge modules.
|
|
3
|
+
*
|
|
4
|
+
* The four main concepts:
|
|
5
|
+
* - {@link MediaInput} — what the user gives us (File / Blob / URL / bytes).
|
|
6
|
+
* - {@link MediaContext} — what we learned about it from probing.
|
|
7
|
+
* - {@link Classification} — which playback strategy we picked.
|
|
8
|
+
* - {@link PlaybackSession} — the running playback, returned by a strategy.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Anything we accept as a media source. We do not accept arbitrary
|
|
12
|
+
* `ReadableStream`s in v1 because we need random access for seeking.
|
|
13
|
+
*/
|
|
14
|
+
type MediaInput = File | Blob | string | URL | ArrayBuffer | Uint8Array;
|
|
15
|
+
/** Container format families we know about. */
|
|
16
|
+
type ContainerKind = "mp4" | "mov" | "mkv" | "webm" | "avi" | "asf" | "flv" | "ogg" | "wav" | "mp3" | "flac" | "adts" | "mpegts" | "unknown";
|
|
17
|
+
/** Video codec families. Strings, not enums, so plugins can extend. */
|
|
18
|
+
type VideoCodec = "h264" | "h265" | "vp8" | "vp9" | "av1" | "mpeg4" | "wmv3" | "vc1" | "rv40" | "mpeg2" | "mpeg1" | "theora" | (string & {});
|
|
19
|
+
/** Audio codec families. */
|
|
20
|
+
type AudioCodec = "aac" | "mp3" | "opus" | "vorbis" | "flac" | "pcm" | "ac3" | "eac3" | "wmav2" | "wmapro" | "alac" | (string & {});
|
|
21
|
+
interface VideoTrackInfo {
|
|
22
|
+
id: number;
|
|
23
|
+
codec: VideoCodec;
|
|
24
|
+
/** Codec-private profile string when known (e.g. "High", "Main 10"). */
|
|
25
|
+
profile?: string;
|
|
26
|
+
level?: number;
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
/** Pixel format string in ffmpeg style (e.g. "yuv420p", "yuv420p10le"). */
|
|
30
|
+
pixelFormat?: string;
|
|
31
|
+
/** Frames per second, when known. */
|
|
32
|
+
fps?: number;
|
|
33
|
+
bitDepth?: number;
|
|
34
|
+
/** RFC 6381 codec string for `MediaSource.isTypeSupported`, when computable. */
|
|
35
|
+
codecString?: string;
|
|
36
|
+
}
|
|
37
|
+
interface AudioTrackInfo {
|
|
38
|
+
id: number;
|
|
39
|
+
codec: AudioCodec;
|
|
40
|
+
channels: number;
|
|
41
|
+
sampleRate: number;
|
|
42
|
+
language?: string;
|
|
43
|
+
codecString?: string;
|
|
44
|
+
}
|
|
45
|
+
interface SubtitleTrackInfo {
|
|
46
|
+
id: number;
|
|
47
|
+
/** "vtt" | "srt" | "ass" | "pgs" | "embedded" */
|
|
48
|
+
format: string;
|
|
49
|
+
language?: string;
|
|
50
|
+
/** Set if this is a sidecar file rather than embedded in the container. */
|
|
51
|
+
sidecarUrl?: string;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Everything the probe layer learned about a source.
|
|
55
|
+
* This is the input to the classification engine.
|
|
56
|
+
*/
|
|
57
|
+
interface MediaContext {
|
|
58
|
+
source: MediaInput;
|
|
59
|
+
/** Stable display name for diagnostics, if we have one. */
|
|
60
|
+
name?: string;
|
|
61
|
+
byteLength?: number;
|
|
62
|
+
container: ContainerKind;
|
|
63
|
+
videoTracks: VideoTrackInfo[];
|
|
64
|
+
audioTracks: AudioTrackInfo[];
|
|
65
|
+
subtitleTracks: SubtitleTrackInfo[];
|
|
66
|
+
/** Which probe backend produced this context, for diagnostics. */
|
|
67
|
+
probedBy: "mediabunny" | "libav" | "sniff";
|
|
68
|
+
/** Total duration in seconds, if known. */
|
|
69
|
+
duration?: number;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* The four playback strategies, ordered from lightest to heaviest:
|
|
73
|
+
* - `"native"` — direct `<video>` playback (zero overhead)
|
|
74
|
+
* - `"remux"` — repackage to fragmented MP4 via MSE (preserves hardware decode)
|
|
75
|
+
* - `"hybrid"` — libav.js demux + WebCodecs hardware decode (for AVI/ASF/FLV with modern codecs)
|
|
76
|
+
* - `"fallback"` — full WASM software decode via libav.js (universal, CPU-intensive)
|
|
77
|
+
*/
|
|
78
|
+
type StrategyName = "native" | "remux" | "hybrid" | "fallback";
|
|
79
|
+
/**
|
|
80
|
+
* Classification outcome from the rules engine. Determines which strategy to use:
|
|
81
|
+
* - `NATIVE` — browser plays this directly
|
|
82
|
+
* - `REMUX_CANDIDATE` — codecs are native, container needs repackaging
|
|
83
|
+
* - `HYBRID_CANDIDATE` — container needs libav demux, codecs are hardware-decodable
|
|
84
|
+
* - `FALLBACK_REQUIRED` — codec has no browser decoder, WASM decode needed
|
|
85
|
+
* - `RISKY_NATIVE` — might work natively but may stall (e.g. Hi10P, 4K120)
|
|
86
|
+
*/
|
|
87
|
+
type StrategyClass = "NATIVE" | "REMUX_CANDIDATE" | "HYBRID_CANDIDATE" | "FALLBACK_REQUIRED" | "RISKY_NATIVE";
|
|
88
|
+
interface Classification {
|
|
89
|
+
class: StrategyClass;
|
|
90
|
+
strategy: StrategyName;
|
|
91
|
+
reason: string;
|
|
92
|
+
/**
|
|
93
|
+
* Ordered list of strategies to try if the primary fails or stalls.
|
|
94
|
+
* The player pops from the front on each escalation.
|
|
95
|
+
*/
|
|
96
|
+
fallbackChain?: StrategyName[];
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* A live playback session created by a strategy. The {@link UnifiedPlayer}
|
|
100
|
+
* delegates user-facing controls to whichever session is currently active.
|
|
101
|
+
*/
|
|
102
|
+
interface PlaybackSession {
|
|
103
|
+
readonly strategy: StrategyName;
|
|
104
|
+
play(): Promise<void>;
|
|
105
|
+
pause(): void;
|
|
106
|
+
seek(time: number): Promise<void>;
|
|
107
|
+
setAudioTrack(id: number): Promise<void>;
|
|
108
|
+
setSubtitleTrack(id: number | null): Promise<void>;
|
|
109
|
+
/** Tear down everything: revoke object URLs, close decoders, etc. */
|
|
110
|
+
destroy(): Promise<void>;
|
|
111
|
+
/** Strategy-specific runtime stats merged into Diagnostics. */
|
|
112
|
+
getRuntimeStats(): Record<string, unknown>;
|
|
113
|
+
/** Current playback position in seconds. Used to capture position before strategy switch. */
|
|
114
|
+
getCurrentTime(): number;
|
|
115
|
+
/** Register a callback for unrecoverable errors that should trigger escalation. */
|
|
116
|
+
onFatalError?(handler: (reason: string) => void): void;
|
|
117
|
+
}
|
|
118
|
+
interface DiagnosticsSnapshot {
|
|
119
|
+
container: ContainerKind | "unknown";
|
|
120
|
+
videoCodec?: VideoCodec;
|
|
121
|
+
audioCodec?: AudioCodec;
|
|
122
|
+
width?: number;
|
|
123
|
+
height?: number;
|
|
124
|
+
fps?: number;
|
|
125
|
+
duration?: number;
|
|
126
|
+
strategy: StrategyName | "pending";
|
|
127
|
+
strategyClass: StrategyClass | "pending";
|
|
128
|
+
reason: string;
|
|
129
|
+
probedBy?: "mediabunny" | "libav" | "sniff";
|
|
130
|
+
/**
|
|
131
|
+
* Where the source is coming from. `"blob"` means File / Blob /
|
|
132
|
+
* ArrayBuffer / Uint8Array (in-memory). `"url"` means an HTTP/HTTPS URL
|
|
133
|
+
* being streamed via Range requests.
|
|
134
|
+
*/
|
|
135
|
+
sourceType?: "blob" | "url";
|
|
136
|
+
/**
|
|
137
|
+
* Transport used to read the source. `"memory"` for in-memory blobs;
|
|
138
|
+
* `"http-range"` for URL sources streamed via HTTP Range requests.
|
|
139
|
+
*/
|
|
140
|
+
transport?: "memory" | "http-range";
|
|
141
|
+
/**
|
|
142
|
+
* For URL sources, true if the server supports HTTP Range requests
|
|
143
|
+
* (the only mode we accept — see `attachLibavHttpReader`). Always true
|
|
144
|
+
* when `transport === "http-range"` because we fail fast otherwise.
|
|
145
|
+
*/
|
|
146
|
+
rangeSupported?: boolean;
|
|
147
|
+
runtime?: Record<string, unknown>;
|
|
148
|
+
strategyHistory?: Array<{
|
|
149
|
+
strategy: StrategyName;
|
|
150
|
+
reason: string;
|
|
151
|
+
at: number;
|
|
152
|
+
}>;
|
|
153
|
+
}
|
|
154
|
+
/** §8.2 plugin interface, kept structurally identical to the design doc. */
|
|
155
|
+
interface Plugin {
|
|
156
|
+
name: string;
|
|
157
|
+
canHandle(context: MediaContext): boolean;
|
|
158
|
+
/** Returns a session if it claims the context, otherwise throws. */
|
|
159
|
+
execute(context: MediaContext, target: HTMLVideoElement): Promise<PlaybackSession>;
|
|
160
|
+
}
|
|
161
|
+
/** Player creation options. */
|
|
162
|
+
interface CreatePlayerOptions {
|
|
163
|
+
source: MediaInput;
|
|
164
|
+
target: HTMLVideoElement;
|
|
165
|
+
/**
|
|
166
|
+
* Optional explicit subtitle list. The player otherwise tries to discover
|
|
167
|
+
* sidecar files via the FileSystemDirectoryHandle (when supplied), or pulls
|
|
168
|
+
* embedded subtitle tracks if the container exposes them.
|
|
169
|
+
*/
|
|
170
|
+
subtitles?: Array<{
|
|
171
|
+
url: string;
|
|
172
|
+
language?: string;
|
|
173
|
+
format?: "vtt" | "srt";
|
|
174
|
+
}>;
|
|
175
|
+
/**
|
|
176
|
+
* Optional directory handle for sidecar discovery. When the source is a
|
|
177
|
+
* `File` selected from this directory, sibling `*.srt`/`*.vtt` files are
|
|
178
|
+
* picked up automatically.
|
|
179
|
+
*/
|
|
180
|
+
directory?: FileSystemDirectoryHandle;
|
|
181
|
+
/**
|
|
182
|
+
* Override the strategy decision. Useful for diagnostics and tests.
|
|
183
|
+
*/
|
|
184
|
+
forceStrategy?: StrategyName;
|
|
185
|
+
/** Inject extra plugins; they take priority over built-ins. */
|
|
186
|
+
plugins?: Plugin[];
|
|
187
|
+
/**
|
|
188
|
+
* When true (default), the player automatically escalates to the next
|
|
189
|
+
* strategy in the fallback chain on failure or stall.
|
|
190
|
+
*/
|
|
191
|
+
autoEscalate?: boolean;
|
|
192
|
+
}
|
|
193
|
+
/** Events emitted by {@link UnifiedPlayer}. Strongly typed. */
|
|
194
|
+
interface PlayerEventMap {
|
|
195
|
+
strategy: {
|
|
196
|
+
strategy: StrategyName;
|
|
197
|
+
reason: string;
|
|
198
|
+
};
|
|
199
|
+
strategychange: {
|
|
200
|
+
from: StrategyName;
|
|
201
|
+
to: StrategyName;
|
|
202
|
+
reason: string;
|
|
203
|
+
currentTime: number;
|
|
204
|
+
};
|
|
205
|
+
tracks: {
|
|
206
|
+
video: VideoTrackInfo[];
|
|
207
|
+
audio: AudioTrackInfo[];
|
|
208
|
+
subtitle: SubtitleTrackInfo[];
|
|
209
|
+
};
|
|
210
|
+
error: Error;
|
|
211
|
+
timeupdate: {
|
|
212
|
+
currentTime: number;
|
|
213
|
+
};
|
|
214
|
+
ended: void;
|
|
215
|
+
ready: void;
|
|
216
|
+
}
|
|
217
|
+
type PlayerEventName = keyof PlayerEventMap;
|
|
218
|
+
/** Generic listener type re-exported for player.on overloads. */
|
|
219
|
+
type Listener<T> = (payload: T) => void;
|
|
220
|
+
/** Target output format for conversion functions. */
|
|
221
|
+
type OutputFormat = "mp4" | "webm" | "mkv";
|
|
222
|
+
/** Options for standalone conversion functions ({@link remux}, transcode). */
|
|
223
|
+
interface ConvertOptions {
|
|
224
|
+
/** Target container format. Default: `"mp4"`. */
|
|
225
|
+
outputFormat?: OutputFormat;
|
|
226
|
+
/** AbortSignal to cancel the operation. */
|
|
227
|
+
signal?: AbortSignal;
|
|
228
|
+
/** Called periodically with progress information. */
|
|
229
|
+
onProgress?: (info: ProgressInfo) => void;
|
|
230
|
+
/** When true, reject on any uncertain codec/container combo. Default: `false` (best-effort). */
|
|
231
|
+
strict?: boolean;
|
|
232
|
+
}
|
|
233
|
+
/** Progress information passed to {@link ConvertOptions.onProgress}. */
|
|
234
|
+
interface ProgressInfo {
|
|
235
|
+
/** Estimated completion percentage, 0–100. */
|
|
236
|
+
percent: number;
|
|
237
|
+
/** Total bytes written to the output so far. */
|
|
238
|
+
bytesWritten: number;
|
|
239
|
+
}
|
|
240
|
+
/** Quality preset for transcode. */
|
|
241
|
+
type TranscodeQuality = "low" | "medium" | "high" | "very-high";
|
|
242
|
+
/** Modern video codecs supported as transcode targets. */
|
|
243
|
+
type OutputVideoCodec = "h264" | "h265" | "vp9" | "av1";
|
|
244
|
+
/** Modern audio codecs supported as transcode targets. */
|
|
245
|
+
type OutputAudioCodec = "aac" | "opus" | "flac";
|
|
246
|
+
/**
|
|
247
|
+
* Hardware acceleration hint for WebCodecs encoders.
|
|
248
|
+
* - `"no-preference"` (default) — let the browser pick
|
|
249
|
+
* - `"prefer-hardware"` — faster, may produce slightly lower quality at low bitrates
|
|
250
|
+
* - `"prefer-software"` — better quality at low bitrates, slower; recommended for archival
|
|
251
|
+
*/
|
|
252
|
+
type HardwareAccelerationHint = "no-preference" | "prefer-hardware" | "prefer-software";
|
|
253
|
+
/** Options for {@link transcode}. Extends {@link ConvertOptions} with codec/quality. */
|
|
254
|
+
interface TranscodeOptions extends ConvertOptions {
|
|
255
|
+
/** Target video codec. Default: `"h264"` for mp4/mkv, `"vp9"` for webm. */
|
|
256
|
+
videoCodec?: OutputVideoCodec;
|
|
257
|
+
/** Target audio codec. Default: `"aac"` for mp4/mkv, `"opus"` for webm. */
|
|
258
|
+
audioCodec?: OutputAudioCodec;
|
|
259
|
+
/** Quality preset. Default: `"medium"`. Maps to mediabunny `Quality` levels. */
|
|
260
|
+
quality?: TranscodeQuality;
|
|
261
|
+
/** Explicit video bitrate in bits per second. Overrides `quality`. */
|
|
262
|
+
videoBitrate?: number;
|
|
263
|
+
/** Explicit audio bitrate in bits per second. Overrides `quality`. */
|
|
264
|
+
audioBitrate?: number;
|
|
265
|
+
/** Target output width in pixels. Height is auto-deduced if not set. */
|
|
266
|
+
width?: number;
|
|
267
|
+
/** Target output height in pixels. Width is auto-deduced if not set. */
|
|
268
|
+
height?: number;
|
|
269
|
+
/** Target output frame rate. */
|
|
270
|
+
frameRate?: number;
|
|
271
|
+
/** Drop the video track entirely (audio-only output). */
|
|
272
|
+
dropVideo?: boolean;
|
|
273
|
+
/** Drop the audio track entirely (silent output). */
|
|
274
|
+
dropAudio?: boolean;
|
|
275
|
+
/**
|
|
276
|
+
* Hardware acceleration hint for the WebCodecs video encoder. Default: `"no-preference"`.
|
|
277
|
+
* Set to `"prefer-software"` for archival-quality encodes at low bitrates;
|
|
278
|
+
* `"prefer-hardware"` for fast batch transcoding where speed matters more than the last
|
|
279
|
+
* few percent of quality.
|
|
280
|
+
*/
|
|
281
|
+
hardwareAcceleration?: HardwareAccelerationHint;
|
|
282
|
+
}
|
|
283
|
+
/** Result of a standalone conversion ({@link remux} or transcode). */
|
|
284
|
+
interface ConvertResult {
|
|
285
|
+
/** The converted file as a Blob, ready for download or further processing. */
|
|
286
|
+
blob: Blob;
|
|
287
|
+
/** Full MIME type string, e.g. `"video/mp4"`. */
|
|
288
|
+
mimeType: string;
|
|
289
|
+
/** Container format name: `"mp4"`, `"webm"`, or `"mkv"`. */
|
|
290
|
+
container: OutputFormat;
|
|
291
|
+
/** Video codec in the output, if present. */
|
|
292
|
+
videoCodec?: string;
|
|
293
|
+
/** Audio codec in the output, if present. */
|
|
294
|
+
audioCodec?: string;
|
|
295
|
+
/** Duration in seconds, if known. */
|
|
296
|
+
duration?: number;
|
|
297
|
+
/** Suggested filename for download. */
|
|
298
|
+
filename?: string;
|
|
299
|
+
/**
|
|
300
|
+
* Diagnostic notes about how the conversion ran. Currently records
|
|
301
|
+
* automatic retry of WebCodecs encoder failures (a known headless
|
|
302
|
+
* Chromium first-call init bug for the H.264 encoder).
|
|
303
|
+
*/
|
|
304
|
+
notes?: string[];
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
declare class UnifiedPlayer {
|
|
308
|
+
private readonly options;
|
|
309
|
+
private readonly registry;
|
|
310
|
+
private emitter;
|
|
311
|
+
private session;
|
|
312
|
+
private diag;
|
|
313
|
+
private timeupdateInterval;
|
|
314
|
+
private mediaContext;
|
|
315
|
+
private classification;
|
|
316
|
+
private stallTimer;
|
|
317
|
+
private lastProgressTime;
|
|
318
|
+
private lastProgressPosition;
|
|
319
|
+
private errorListener;
|
|
320
|
+
private switchingPromise;
|
|
321
|
+
/**
|
|
322
|
+
* @internal Use {@link createPlayer} or {@link UnifiedPlayer.create} instead.
|
|
323
|
+
*/
|
|
324
|
+
private constructor();
|
|
325
|
+
static create(options: CreatePlayerOptions): Promise<UnifiedPlayer>;
|
|
326
|
+
private bootstrap;
|
|
327
|
+
/**
|
|
328
|
+
* Try to start a session with the given strategy. On failure, walk the
|
|
329
|
+
* fallback chain. Throws only if all strategies are exhausted.
|
|
330
|
+
*/
|
|
331
|
+
private startSession;
|
|
332
|
+
private escalate;
|
|
333
|
+
private doEscalate;
|
|
334
|
+
private attachSupervisor;
|
|
335
|
+
private clearSupervisor;
|
|
336
|
+
/** Manually switch to a different playback strategy. Preserves current position and play/pause state. Concurrent calls are serialized. */
|
|
337
|
+
setStrategy(strategy: StrategyName, reason?: string): Promise<void>;
|
|
338
|
+
private doSetStrategy;
|
|
339
|
+
private startTimeupdateLoop;
|
|
340
|
+
/** Subscribe to a player event. Returns an unsubscribe function. Sticky events (strategy, ready, tracks) replay for late subscribers. */
|
|
341
|
+
on<K extends PlayerEventName>(event: K, fn: Listener<PlayerEventMap[K]>): () => void;
|
|
342
|
+
/** Remove a previously registered event listener. */
|
|
343
|
+
off<K extends PlayerEventName>(event: K, fn: Listener<PlayerEventMap[K]>): void;
|
|
344
|
+
/** Begin or resume playback. Throws if the player is not ready. */
|
|
345
|
+
play(): Promise<void>;
|
|
346
|
+
/** Pause playback. No-op if the player is not ready or already paused. */
|
|
347
|
+
pause(): void;
|
|
348
|
+
/** Seek to the given time in seconds. Throws if the player is not ready. */
|
|
349
|
+
seek(time: number): Promise<void>;
|
|
350
|
+
/** Switch the active audio track by track ID. Throws if the player is not ready. */
|
|
351
|
+
setAudioTrack(id: number): Promise<void>;
|
|
352
|
+
/** Switch the active subtitle track by track ID, or pass `null` to disable subtitles. */
|
|
353
|
+
setSubtitleTrack(id: number | null): Promise<void>;
|
|
354
|
+
/** Return a snapshot of current diagnostics: container, codecs, strategy, runtime stats, and strategy history. */
|
|
355
|
+
getDiagnostics(): DiagnosticsSnapshot;
|
|
356
|
+
/** Return the total duration in seconds, or `NaN` if unknown. */
|
|
357
|
+
getDuration(): number;
|
|
358
|
+
/** Return the current playback position in seconds. */
|
|
359
|
+
getCurrentTime(): number;
|
|
360
|
+
/** Tear down the player: stop timers, destroy the active session, remove all event listeners. The player is unusable after this call. */
|
|
361
|
+
destroy(): Promise<void>;
|
|
362
|
+
}
|
|
363
|
+
declare function createPlayer(options: CreatePlayerOptions): Promise<UnifiedPlayer>;
|
|
364
|
+
|
|
365
|
+
export { type AudioCodec as A, type Classification as C, type DiagnosticsSnapshot as D, type HardwareAccelerationHint as H, type MediaContext as M, type OutputAudioCodec as O, type PlaybackSession as P, type StrategyClass as S, type TranscodeOptions as T, UnifiedPlayer as U, type VideoCodec as V, type MediaInput as a, type ConvertOptions as b, type ConvertResult as c, type AudioTrackInfo as d, type ContainerKind as e, type CreatePlayerOptions as f, type OutputFormat as g, type OutputVideoCodec as h, type PlayerEventMap as i, type PlayerEventName as j, type Plugin as k, type ProgressInfo as l, type StrategyName as m, type SubtitleTrackInfo as n, type TranscodeQuality as o, type VideoTrackInfo as p, createPlayer as q };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkY5FYF5KG_cjs = require('./chunk-Y5FYF5KG.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, "isInMemorySource", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return chunkY5FYF5KG_cjs.isInMemorySource; }
|
|
10
|
+
});
|
|
11
|
+
Object.defineProperty(exports, "normalizeSource", {
|
|
12
|
+
enumerable: true,
|
|
13
|
+
get: function () { return chunkY5FYF5KG_cjs.normalizeSource; }
|
|
14
|
+
});
|
|
15
|
+
Object.defineProperty(exports, "sniffContainer", {
|
|
16
|
+
enumerable: true,
|
|
17
|
+
get: function () { return chunkY5FYF5KG_cjs.sniffContainer; }
|
|
18
|
+
});
|
|
19
|
+
Object.defineProperty(exports, "sniffContainerFromBytes", {
|
|
20
|
+
enumerable: true,
|
|
21
|
+
get: function () { return chunkY5FYF5KG_cjs.sniffContainerFromBytes; }
|
|
22
|
+
});
|
|
23
|
+
Object.defineProperty(exports, "sniffNormalizedSource", {
|
|
24
|
+
enumerable: true,
|
|
25
|
+
get: function () { return chunkY5FYF5KG_cjs.sniffNormalizedSource; }
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=source-SC6ZEQYR.cjs.map
|
|
28
|
+
//# sourceMappingURL=source-SC6ZEQYR.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"source-SC6ZEQYR.cjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"source-ZFS4H7J3.js"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkNZU7W256_cjs = require('./chunk-NZU7W256.cjs');
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
Object.defineProperty(exports, "pickLibavVariant", {
|
|
8
|
+
enumerable: true,
|
|
9
|
+
get: function () { return chunkNZU7W256_cjs.pickLibavVariant; }
|
|
10
|
+
});
|
|
11
|
+
//# sourceMappingURL=variant-routing-GOHB2RZN.cjs.map
|
|
12
|
+
//# sourceMappingURL=variant-routing-GOHB2RZN.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"variant-routing-GOHB2RZN.cjs"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"names":[],"mappings":"","file":"variant-routing-JOBWXYKD.js"}
|
package/package.json
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "avbridge",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Play and convert arbitrary video files in the browser. Native, remux, hybrid, fallback, and transcode — one API.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Keishi Hattori",
|
|
7
|
+
"homepage": "https://github.com/keishi/avbridge#readme",
|
|
8
|
+
"repository": {
|
|
9
|
+
"type": "git",
|
|
10
|
+
"url": "git+https://github.com/keishi/avbridge.git"
|
|
11
|
+
},
|
|
12
|
+
"bugs": {
|
|
13
|
+
"url": "https://github.com/keishi/avbridge/issues"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"media-player",
|
|
17
|
+
"video",
|
|
18
|
+
"audio",
|
|
19
|
+
"browser",
|
|
20
|
+
"transcode",
|
|
21
|
+
"remux",
|
|
22
|
+
"webcodecs",
|
|
23
|
+
"mse",
|
|
24
|
+
"mediabunny",
|
|
25
|
+
"avi",
|
|
26
|
+
"mkv",
|
|
27
|
+
"wmv",
|
|
28
|
+
"divx",
|
|
29
|
+
"mpegts",
|
|
30
|
+
"libav",
|
|
31
|
+
"wasm",
|
|
32
|
+
"web-component"
|
|
33
|
+
],
|
|
34
|
+
"type": "module",
|
|
35
|
+
"sideEffects": [
|
|
36
|
+
"./dist/element.js",
|
|
37
|
+
"./dist/element.cjs"
|
|
38
|
+
],
|
|
39
|
+
"main": "./dist/index.cjs",
|
|
40
|
+
"module": "./dist/index.js",
|
|
41
|
+
"types": "./dist/index.d.ts",
|
|
42
|
+
"exports": {
|
|
43
|
+
".": {
|
|
44
|
+
"types": "./dist/index.d.ts",
|
|
45
|
+
"import": "./dist/index.js",
|
|
46
|
+
"require": "./dist/index.cjs"
|
|
47
|
+
},
|
|
48
|
+
"./element": {
|
|
49
|
+
"types": "./dist/element.d.ts",
|
|
50
|
+
"import": "./dist/element.js",
|
|
51
|
+
"require": "./dist/element.cjs"
|
|
52
|
+
}
|
|
53
|
+
},
|
|
54
|
+
"files": [
|
|
55
|
+
"dist",
|
|
56
|
+
"src",
|
|
57
|
+
"README.md",
|
|
58
|
+
"CHANGELOG.md",
|
|
59
|
+
"LICENSE"
|
|
60
|
+
],
|
|
61
|
+
"scripts": {
|
|
62
|
+
"build": "tsup",
|
|
63
|
+
"typecheck": "tsc --noEmit",
|
|
64
|
+
"test": "vitest run",
|
|
65
|
+
"test:watch": "vitest",
|
|
66
|
+
"predemo": "node scripts/copy-libav.mjs",
|
|
67
|
+
"demo": "vite",
|
|
68
|
+
"predemo:build": "node scripts/copy-libav.mjs",
|
|
69
|
+
"demo:build": "vite build",
|
|
70
|
+
"build:libav": "./scripts/build-libav.sh",
|
|
71
|
+
"test:playback": "node scripts/playback-test.mjs",
|
|
72
|
+
"test:convert": "node scripts/convert-test.mjs",
|
|
73
|
+
"test:element": "node scripts/element-test.mjs",
|
|
74
|
+
"test:url-streaming": "node scripts/url-streaming-test.mjs",
|
|
75
|
+
"fixtures": "node scripts/generate-fixtures.mjs",
|
|
76
|
+
"audit:bundle": "node scripts/bundle-audit.mjs"
|
|
77
|
+
},
|
|
78
|
+
"dependencies": {
|
|
79
|
+
"mediabunny": "^1.40.1"
|
|
80
|
+
},
|
|
81
|
+
"optionalDependencies": {
|
|
82
|
+
"@libav.js/types": "^6.8.8",
|
|
83
|
+
"@libav.js/variant-webcodecs": "^6.8.8",
|
|
84
|
+
"libavjs-webcodecs-bridge": "^0.3.2"
|
|
85
|
+
},
|
|
86
|
+
"devDependencies": {
|
|
87
|
+
"@types/node": "^20.11.0",
|
|
88
|
+
"jsdom": "^24.0.0",
|
|
89
|
+
"puppeteer": "^24.40.0",
|
|
90
|
+
"tsup": "^8.0.0",
|
|
91
|
+
"typescript": "^5.4.0",
|
|
92
|
+
"vite": "^5.2.0",
|
|
93
|
+
"vitest": "^1.5.0"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { classifyContext as classify } from "./rules.js";
|