avbridge 2.1.2 → 2.2.1

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.
Files changed (67) hide show
  1. package/CHANGELOG.md +138 -0
  2. package/README.md +98 -71
  3. package/dist/{avi-GNTV5ZOH.cjs → avi-6SJLWIWW.cjs} +19 -4
  4. package/dist/avi-6SJLWIWW.cjs.map +1 -0
  5. package/dist/{avi-V6HYQVR2.js → avi-GCGM7OJI.js} +18 -3
  6. package/dist/avi-GCGM7OJI.js.map +1 -0
  7. package/dist/{chunk-EJH67FXG.js → chunk-5DMTJVIU.js} +99 -3
  8. package/dist/chunk-5DMTJVIU.js.map +1 -0
  9. package/dist/{chunk-3AUGRKPY.js → chunk-DMWARSEF.js} +160 -27
  10. package/dist/chunk-DMWARSEF.js.map +1 -0
  11. package/dist/{chunk-JQH6D4OE.cjs → chunk-G4APZMCP.cjs} +100 -3
  12. package/dist/chunk-G4APZMCP.cjs.map +1 -0
  13. package/dist/{chunk-Y5FYF5KG.cjs → chunk-HZLQNKFN.cjs} +5 -2
  14. package/dist/chunk-HZLQNKFN.cjs.map +1 -0
  15. package/dist/{chunk-PQTZS7OA.js → chunk-ILKDNBSE.js} +5 -2
  16. package/dist/chunk-ILKDNBSE.js.map +1 -0
  17. package/dist/{chunk-DPVIOYGC.cjs → chunk-UF2N5L63.cjs} +164 -31
  18. package/dist/chunk-UF2N5L63.cjs.map +1 -0
  19. package/dist/element-browser.js +276 -21
  20. package/dist/element-browser.js.map +1 -1
  21. package/dist/element.cjs +4 -4
  22. package/dist/element.d.cts +1 -1
  23. package/dist/element.d.ts +1 -1
  24. package/dist/element.js +3 -3
  25. package/dist/index.cjs +18 -18
  26. package/dist/index.d.cts +2 -2
  27. package/dist/index.d.ts +2 -2
  28. package/dist/index.js +5 -5
  29. package/dist/libav-loader-27RDIN2I.js +3 -0
  30. package/dist/{libav-loader-XKH2TKUW.js.map → libav-loader-27RDIN2I.js.map} +1 -1
  31. package/dist/libav-loader-IV4AJ2HW.cjs +12 -0
  32. package/dist/{libav-loader-6APXVNIV.cjs.map → libav-loader-IV4AJ2HW.cjs.map} +1 -1
  33. package/dist/{player-BdtUG4rh.d.cts → player-U2NPmFvA.d.cts} +4 -3
  34. package/dist/{player-BdtUG4rh.d.ts → player-U2NPmFvA.d.ts} +4 -3
  35. package/dist/source-CN43EI7Z.cjs +28 -0
  36. package/dist/{source-SC6ZEQYR.cjs.map → source-CN43EI7Z.cjs.map} +1 -1
  37. package/dist/source-FFZ7TW2B.js +3 -0
  38. package/dist/{source-ZFS4H7J3.js.map → source-FFZ7TW2B.js.map} +1 -1
  39. package/package.json +1 -1
  40. package/src/classify/rules.ts +9 -2
  41. package/src/player.ts +46 -17
  42. package/src/probe/avi.ts +8 -1
  43. package/src/strategies/fallback/audio-output.ts +25 -3
  44. package/src/strategies/fallback/decoder.ts +96 -8
  45. package/src/strategies/fallback/index.ts +98 -6
  46. package/src/strategies/fallback/libav-loader.ts +12 -0
  47. package/src/strategies/fallback/video-renderer.ts +5 -1
  48. package/src/strategies/hybrid/index.ts +9 -1
  49. package/src/strategies/remux/index.ts +13 -1
  50. package/src/strategies/remux/pipeline.ts +6 -0
  51. package/src/types.ts +10 -1
  52. package/src/util/debug.ts +131 -0
  53. package/src/util/source.ts +4 -0
  54. package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.mjs +1 -1
  55. package/vendor/libav/avbridge/libav-6.8.8.0-avbridge.wasm.wasm +0 -0
  56. package/dist/avi-GNTV5ZOH.cjs.map +0 -1
  57. package/dist/avi-V6HYQVR2.js.map +0 -1
  58. package/dist/chunk-3AUGRKPY.js.map +0 -1
  59. package/dist/chunk-DPVIOYGC.cjs.map +0 -1
  60. package/dist/chunk-EJH67FXG.js.map +0 -1
  61. package/dist/chunk-JQH6D4OE.cjs.map +0 -1
  62. package/dist/chunk-PQTZS7OA.js.map +0 -1
  63. package/dist/chunk-Y5FYF5KG.cjs.map +0 -1
  64. package/dist/libav-loader-6APXVNIV.cjs +0 -12
  65. package/dist/libav-loader-XKH2TKUW.js +0 -3
  66. package/dist/source-SC6ZEQYR.cjs +0 -28
  67. package/dist/source-ZFS4H7J3.js +0 -3
package/dist/element.cjs CHANGED
@@ -1,8 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkDPVIOYGC_cjs = require('./chunk-DPVIOYGC.cjs');
4
- require('./chunk-Y5FYF5KG.cjs');
5
- require('./chunk-JQH6D4OE.cjs');
3
+ var chunkUF2N5L63_cjs = require('./chunk-UF2N5L63.cjs');
4
+ require('./chunk-HZLQNKFN.cjs');
5
+ require('./chunk-G4APZMCP.cjs');
6
6
  require('./chunk-NZU7W256.cjs');
7
7
 
8
8
  // src/element/avbridge-video.ts
@@ -226,7 +226,7 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
226
226
  this._dispatch("loadstart", {});
227
227
  let player;
228
228
  try {
229
- player = await chunkDPVIOYGC_cjs.createPlayer({
229
+ player = await chunkUF2N5L63_cjs.createPlayer({
230
230
  source,
231
231
  target: this._videoEl,
232
232
  // Honor the consumer's preferred initial strategy. "auto" means
@@ -1,4 +1,4 @@
1
- import { a as MediaInput, m as StrategyName, S as StrategyClass, U as UnifiedPlayer, d as AudioTrackInfo, n as SubtitleTrackInfo, D as DiagnosticsSnapshot } from './player-BdtUG4rh.cjs';
1
+ import { a as MediaInput, m as StrategyName, S as StrategyClass, U as UnifiedPlayer, d as AudioTrackInfo, n as SubtitleTrackInfo, D as DiagnosticsSnapshot } from './player-U2NPmFvA.cjs';
2
2
 
3
3
  /**
4
4
  * `<avbridge-video>` — `HTMLMediaElement`-compatible primitive backed by the
package/dist/element.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { a as MediaInput, m as StrategyName, S as StrategyClass, U as UnifiedPlayer, d as AudioTrackInfo, n as SubtitleTrackInfo, D as DiagnosticsSnapshot } from './player-BdtUG4rh.js';
1
+ import { a as MediaInput, m as StrategyName, S as StrategyClass, U as UnifiedPlayer, d as AudioTrackInfo, n as SubtitleTrackInfo, D as DiagnosticsSnapshot } from './player-U2NPmFvA.js';
2
2
 
3
3
  /**
4
4
  * `<avbridge-video>` — `HTMLMediaElement`-compatible primitive backed by the
package/dist/element.js CHANGED
@@ -1,6 +1,6 @@
1
- import { createPlayer } from './chunk-3AUGRKPY.js';
2
- import './chunk-PQTZS7OA.js';
3
- import './chunk-EJH67FXG.js';
1
+ import { createPlayer } from './chunk-DMWARSEF.js';
2
+ import './chunk-ILKDNBSE.js';
3
+ import './chunk-5DMTJVIU.js';
4
4
  import './chunk-J5MCMN3S.js';
5
5
 
6
6
  // src/element/avbridge-video.ts
package/dist/index.cjs CHANGED
@@ -1,9 +1,9 @@
1
1
  'use strict';
2
2
 
3
- var chunkDPVIOYGC_cjs = require('./chunk-DPVIOYGC.cjs');
4
- var chunkY5FYF5KG_cjs = require('./chunk-Y5FYF5KG.cjs');
3
+ var chunkUF2N5L63_cjs = require('./chunk-UF2N5L63.cjs');
4
+ var chunkHZLQNKFN_cjs = require('./chunk-HZLQNKFN.cjs');
5
5
  var chunkL4NPOJ36_cjs = require('./chunk-L4NPOJ36.cjs');
6
- require('./chunk-JQH6D4OE.cjs');
6
+ require('./chunk-G4APZMCP.cjs');
7
7
  require('./chunk-NZU7W256.cjs');
8
8
 
9
9
  // src/convert/remux.ts
@@ -21,7 +21,7 @@ var MEDIABUNNY_CONTAINERS = /* @__PURE__ */ new Set([
21
21
  async function remux(source, options = {}) {
22
22
  const outputFormat = options.outputFormat ?? "mp4";
23
23
  options.signal?.throwIfAborted();
24
- const ctx = await chunkDPVIOYGC_cjs.probe(source);
24
+ const ctx = await chunkUF2N5L63_cjs.probe(source);
25
25
  options.signal?.throwIfAborted();
26
26
  validateRemuxEligibility(ctx, options.strict ?? false);
27
27
  if (MEDIABUNNY_CONTAINERS.has(ctx.container)) {
@@ -33,7 +33,7 @@ function validateRemuxEligibility(ctx, strict) {
33
33
  const video = ctx.videoTracks[0];
34
34
  const audio = ctx.audioTracks[0];
35
35
  if (video) {
36
- const mbCodec = chunkDPVIOYGC_cjs.avbridgeVideoToMediabunny(video.codec);
36
+ const mbCodec = chunkUF2N5L63_cjs.avbridgeVideoToMediabunny(video.codec);
37
37
  if (!mbCodec) {
38
38
  throw new Error(
39
39
  `Cannot remux: video codec "${video.codec}" is not supported for remuxing. Use transcode() to re-encode to a modern codec.`
@@ -41,7 +41,7 @@ function validateRemuxEligibility(ctx, strict) {
41
41
  }
42
42
  }
43
43
  if (audio) {
44
- const mbCodec = chunkDPVIOYGC_cjs.avbridgeAudioToMediabunny(audio.codec);
44
+ const mbCodec = chunkUF2N5L63_cjs.avbridgeAudioToMediabunny(audio.codec);
45
45
  if (!mbCodec) {
46
46
  throw new Error(
47
47
  `Cannot remux: audio codec "${audio.codec}" is not supported for remuxing. Use transcode() to re-encode to a modern codec.`
@@ -60,7 +60,7 @@ function validateRemuxEligibility(ctx, strict) {
60
60
  async function remuxViaMediAbunny(ctx, outputFormat, options) {
61
61
  const mb = await import('mediabunny');
62
62
  const input = new mb.Input({
63
- source: await chunkDPVIOYGC_cjs.buildMediabunnySourceFromInput(mb, ctx.source),
63
+ source: await chunkUF2N5L63_cjs.buildMediabunnySourceFromInput(mb, ctx.source),
64
64
  formats: mb.ALL_FORMATS
65
65
  });
66
66
  const target = new mb.BufferTarget();
@@ -117,7 +117,7 @@ async function remuxViaLibav(ctx, outputFormat, options) {
117
117
  let loadLibav;
118
118
  let pickLibavVariant;
119
119
  try {
120
- const loader = await import('./libav-loader-6APXVNIV.cjs');
120
+ const loader = await import('./libav-loader-IV4AJ2HW.cjs');
121
121
  const routing = await import('./variant-routing-GOHB2RZN.cjs');
122
122
  loadLibav = loader.loadLibav;
123
123
  pickLibavVariant = routing.pickLibavVariant;
@@ -128,7 +128,7 @@ async function remuxViaLibav(ctx, outputFormat, options) {
128
128
  }
129
129
  const variant = pickLibavVariant(ctx);
130
130
  const libav = await loadLibav(variant);
131
- const normalized = await chunkY5FYF5KG_cjs.normalizeSource(ctx.source);
131
+ const normalized = await chunkHZLQNKFN_cjs.normalizeSource(ctx.source);
132
132
  const filename = ctx.name ?? `remux-input-${Date.now()}`;
133
133
  const handle = await chunkL4NPOJ36_cjs.prepareLibavInput(libav, filename, normalized);
134
134
  try {
@@ -146,8 +146,8 @@ async function doLibavRemux(libav, filename, ctx, outputFormat, options) {
146
146
  const audioStream = streams.find((s) => s.codec_type === libav.AVMEDIA_TYPE_AUDIO) ?? null;
147
147
  const videoTrackInfo = ctx.videoTracks[0];
148
148
  const audioTrackInfo = ctx.audioTracks[0];
149
- const mbVideoCodec = videoTrackInfo ? chunkDPVIOYGC_cjs.avbridgeVideoToMediabunny(videoTrackInfo.codec) : null;
150
- const mbAudioCodec = audioTrackInfo ? chunkDPVIOYGC_cjs.avbridgeAudioToMediabunny(audioTrackInfo.codec) : null;
149
+ const mbVideoCodec = videoTrackInfo ? chunkUF2N5L63_cjs.avbridgeVideoToMediabunny(videoTrackInfo.codec) : null;
150
+ const mbAudioCodec = audioTrackInfo ? chunkUF2N5L63_cjs.avbridgeAudioToMediabunny(audioTrackInfo.codec) : null;
151
151
  const target = new mb.BufferTarget();
152
152
  const output = new mb.Output({
153
153
  format: createOutputFormat(mb, outputFormat),
@@ -358,7 +358,7 @@ async function transcode(source, options = {}) {
358
358
  const quality = options.quality ?? "medium";
359
359
  validateCodecCompatibility(outputFormat, videoCodec, audioCodec);
360
360
  options.signal?.throwIfAborted();
361
- const ctx = await chunkDPVIOYGC_cjs.probe(source);
361
+ const ctx = await chunkUF2N5L63_cjs.probe(source);
362
362
  options.signal?.throwIfAborted();
363
363
  if (!MEDIABUNNY_CONTAINERS2.has(ctx.container)) {
364
364
  throw new Error(
@@ -370,7 +370,7 @@ async function transcode(source, options = {}) {
370
370
  async function attemptTranscode(ctx, outputFormat, videoCodec, audioCodec, quality, options) {
371
371
  const mb = await import('mediabunny');
372
372
  const input = new mb.Input({
373
- source: await chunkDPVIOYGC_cjs.buildMediabunnySourceFromInput(mb, ctx.source),
373
+ source: await chunkUF2N5L63_cjs.buildMediabunnySourceFromInput(mb, ctx.source),
374
374
  formats: mb.ALL_FORMATS
375
375
  });
376
376
  const target = new mb.BufferTarget();
@@ -552,23 +552,23 @@ function qualityToMediabunny(mb, quality) {
552
552
 
553
553
  Object.defineProperty(exports, "UnifiedPlayer", {
554
554
  enumerable: true,
555
- get: function () { return chunkDPVIOYGC_cjs.UnifiedPlayer; }
555
+ get: function () { return chunkUF2N5L63_cjs.UnifiedPlayer; }
556
556
  });
557
557
  Object.defineProperty(exports, "classify", {
558
558
  enumerable: true,
559
- get: function () { return chunkDPVIOYGC_cjs.classifyContext; }
559
+ get: function () { return chunkUF2N5L63_cjs.classifyContext; }
560
560
  });
561
561
  Object.defineProperty(exports, "createPlayer", {
562
562
  enumerable: true,
563
- get: function () { return chunkDPVIOYGC_cjs.createPlayer; }
563
+ get: function () { return chunkUF2N5L63_cjs.createPlayer; }
564
564
  });
565
565
  Object.defineProperty(exports, "probe", {
566
566
  enumerable: true,
567
- get: function () { return chunkDPVIOYGC_cjs.probe; }
567
+ get: function () { return chunkUF2N5L63_cjs.probe; }
568
568
  });
569
569
  Object.defineProperty(exports, "srtToVtt", {
570
570
  enumerable: true,
571
- get: function () { return chunkDPVIOYGC_cjs.srtToVtt; }
571
+ get: function () { return chunkUF2N5L63_cjs.srtToVtt; }
572
572
  });
573
573
  exports.remux = remux;
574
574
  exports.transcode = transcode;
package/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MediaContext, C as Classification, a as MediaInput, b as ConvertOptions, c as ConvertResult, T as TranscodeOptions } from './player-BdtUG4rh.cjs';
2
- export { A as AudioCodec, d as AudioTrackInfo, e as ContainerKind, f as CreatePlayerOptions, D as DiagnosticsSnapshot, H as HardwareAccelerationHint, O as OutputAudioCodec, g as OutputFormat, h as OutputVideoCodec, P as PlaybackSession, i as PlayerEventMap, j as PlayerEventName, k as Plugin, l as ProgressInfo, S as StrategyClass, m as StrategyName, n as SubtitleTrackInfo, o as TranscodeQuality, U as UnifiedPlayer, V as VideoCodec, p as VideoTrackInfo, q as createPlayer } from './player-BdtUG4rh.cjs';
1
+ import { M as MediaContext, C as Classification, a as MediaInput, b as ConvertOptions, c as ConvertResult, T as TranscodeOptions } from './player-U2NPmFvA.cjs';
2
+ export { A as AudioCodec, d as AudioTrackInfo, e as ContainerKind, f as CreatePlayerOptions, D as DiagnosticsSnapshot, H as HardwareAccelerationHint, O as OutputAudioCodec, g as OutputFormat, h as OutputVideoCodec, P as PlaybackSession, i as PlayerEventMap, j as PlayerEventName, k as Plugin, l as ProgressInfo, S as StrategyClass, m as StrategyName, n as SubtitleTrackInfo, o as TranscodeQuality, U as UnifiedPlayer, V as VideoCodec, p as VideoTrackInfo, q as createPlayer } from './player-U2NPmFvA.cjs';
3
3
 
4
4
  /**
5
5
  * Pure classification — no I/O, no async. Test-friendly.
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { M as MediaContext, C as Classification, a as MediaInput, b as ConvertOptions, c as ConvertResult, T as TranscodeOptions } from './player-BdtUG4rh.js';
2
- export { A as AudioCodec, d as AudioTrackInfo, e as ContainerKind, f as CreatePlayerOptions, D as DiagnosticsSnapshot, H as HardwareAccelerationHint, O as OutputAudioCodec, g as OutputFormat, h as OutputVideoCodec, P as PlaybackSession, i as PlayerEventMap, j as PlayerEventName, k as Plugin, l as ProgressInfo, S as StrategyClass, m as StrategyName, n as SubtitleTrackInfo, o as TranscodeQuality, U as UnifiedPlayer, V as VideoCodec, p as VideoTrackInfo, q as createPlayer } from './player-BdtUG4rh.js';
1
+ import { M as MediaContext, C as Classification, a as MediaInput, b as ConvertOptions, c as ConvertResult, T as TranscodeOptions } from './player-U2NPmFvA.js';
2
+ export { A as AudioCodec, d as AudioTrackInfo, e as ContainerKind, f as CreatePlayerOptions, D as DiagnosticsSnapshot, H as HardwareAccelerationHint, O as OutputAudioCodec, g as OutputFormat, h as OutputVideoCodec, P as PlaybackSession, i as PlayerEventMap, j as PlayerEventName, k as Plugin, l as ProgressInfo, S as StrategyClass, m as StrategyName, n as SubtitleTrackInfo, o as TranscodeQuality, U as UnifiedPlayer, V as VideoCodec, p as VideoTrackInfo, q as createPlayer } from './player-U2NPmFvA.js';
3
3
 
4
4
  /**
5
5
  * Pure classification — no I/O, no async. Test-friendly.
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
- import { probe, avbridgeVideoToMediabunny, avbridgeAudioToMediabunny, buildMediabunnySourceFromInput } from './chunk-3AUGRKPY.js';
2
- export { UnifiedPlayer, classifyContext as classify, createPlayer, probe, srtToVtt } from './chunk-3AUGRKPY.js';
3
- import { normalizeSource } from './chunk-PQTZS7OA.js';
1
+ import { probe, avbridgeVideoToMediabunny, avbridgeAudioToMediabunny, buildMediabunnySourceFromInput } from './chunk-DMWARSEF.js';
2
+ export { UnifiedPlayer, classifyContext as classify, createPlayer, probe, srtToVtt } from './chunk-DMWARSEF.js';
3
+ import { normalizeSource } from './chunk-ILKDNBSE.js';
4
4
  import { prepareLibavInput } from './chunk-WD2ZNQA7.js';
5
- import './chunk-EJH67FXG.js';
5
+ import './chunk-5DMTJVIU.js';
6
6
  import './chunk-J5MCMN3S.js';
7
7
 
8
8
  // src/convert/remux.ts
@@ -116,7 +116,7 @@ async function remuxViaLibav(ctx, outputFormat, options) {
116
116
  let loadLibav;
117
117
  let pickLibavVariant;
118
118
  try {
119
- const loader = await import('./libav-loader-XKH2TKUW.js');
119
+ const loader = await import('./libav-loader-27RDIN2I.js');
120
120
  const routing = await import('./variant-routing-JOBWXYKD.js');
121
121
  loadLibav = loader.loadLibav;
122
122
  pickLibavVariant = routing.pickLibavVariant;
@@ -0,0 +1,3 @@
1
+ export { loadLibav } from './chunk-5DMTJVIU.js';
2
+ //# sourceMappingURL=libav-loader-27RDIN2I.js.map
3
+ //# sourceMappingURL=libav-loader-27RDIN2I.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"libav-loader-XKH2TKUW.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"libav-loader-27RDIN2I.js"}
@@ -0,0 +1,12 @@
1
+ 'use strict';
2
+
3
+ var chunkG4APZMCP_cjs = require('./chunk-G4APZMCP.cjs');
4
+
5
+
6
+
7
+ Object.defineProperty(exports, "loadLibav", {
8
+ enumerable: true,
9
+ get: function () { return chunkG4APZMCP_cjs.loadLibav; }
10
+ });
11
+ //# sourceMappingURL=libav-loader-IV4AJ2HW.cjs.map
12
+ //# sourceMappingURL=libav-loader-IV4AJ2HW.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"libav-loader-6APXVNIV.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"libav-loader-IV4AJ2HW.cjs"}
@@ -13,11 +13,11 @@
13
13
  */
14
14
  type MediaInput = File | Blob | string | URL | ArrayBuffer | Uint8Array;
15
15
  /** Container format families we know about. */
16
- type ContainerKind = "mp4" | "mov" | "mkv" | "webm" | "avi" | "asf" | "flv" | "ogg" | "wav" | "mp3" | "flac" | "adts" | "mpegts" | "unknown";
16
+ type ContainerKind = "mp4" | "mov" | "mkv" | "webm" | "avi" | "asf" | "flv" | "rm" | "ogg" | "wav" | "mp3" | "flac" | "adts" | "mpegts" | "unknown";
17
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 & {});
18
+ type VideoCodec = "h264" | "h265" | "vp8" | "vp9" | "av1" | "mpeg4" | "wmv3" | "vc1" | "rv10" | "rv20" | "rv30" | "rv40" | "mpeg2" | "mpeg1" | "theora" | (string & {});
19
19
  /** Audio codec families. */
20
- type AudioCodec = "aac" | "mp3" | "opus" | "vorbis" | "flac" | "pcm" | "ac3" | "eac3" | "wmav2" | "wmapro" | "alac" | (string & {});
20
+ type AudioCodec = "aac" | "mp3" | "opus" | "vorbis" | "flac" | "pcm" | "ac3" | "eac3" | "wmav2" | "wmapro" | "alac" | "cook" | "ra_144" | "ra_288" | "sipr" | "atrac3" | (string & {});
21
21
  interface VideoTrackInfo {
22
22
  id: number;
23
23
  codec: VideoCodec;
@@ -324,6 +324,7 @@ declare class UnifiedPlayer {
324
324
  private lastProgressTime;
325
325
  private lastProgressPosition;
326
326
  private errorListener;
327
+ private endedListener;
327
328
  private switchingPromise;
328
329
  private subtitleResources;
329
330
  /**
@@ -13,11 +13,11 @@
13
13
  */
14
14
  type MediaInput = File | Blob | string | URL | ArrayBuffer | Uint8Array;
15
15
  /** Container format families we know about. */
16
- type ContainerKind = "mp4" | "mov" | "mkv" | "webm" | "avi" | "asf" | "flv" | "ogg" | "wav" | "mp3" | "flac" | "adts" | "mpegts" | "unknown";
16
+ type ContainerKind = "mp4" | "mov" | "mkv" | "webm" | "avi" | "asf" | "flv" | "rm" | "ogg" | "wav" | "mp3" | "flac" | "adts" | "mpegts" | "unknown";
17
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 & {});
18
+ type VideoCodec = "h264" | "h265" | "vp8" | "vp9" | "av1" | "mpeg4" | "wmv3" | "vc1" | "rv10" | "rv20" | "rv30" | "rv40" | "mpeg2" | "mpeg1" | "theora" | (string & {});
19
19
  /** Audio codec families. */
20
- type AudioCodec = "aac" | "mp3" | "opus" | "vorbis" | "flac" | "pcm" | "ac3" | "eac3" | "wmav2" | "wmapro" | "alac" | (string & {});
20
+ type AudioCodec = "aac" | "mp3" | "opus" | "vorbis" | "flac" | "pcm" | "ac3" | "eac3" | "wmav2" | "wmapro" | "alac" | "cook" | "ra_144" | "ra_288" | "sipr" | "atrac3" | (string & {});
21
21
  interface VideoTrackInfo {
22
22
  id: number;
23
23
  codec: VideoCodec;
@@ -324,6 +324,7 @@ declare class UnifiedPlayer {
324
324
  private lastProgressTime;
325
325
  private lastProgressPosition;
326
326
  private errorListener;
327
+ private endedListener;
327
328
  private switchingPromise;
328
329
  private subtitleResources;
329
330
  /**
@@ -0,0 +1,28 @@
1
+ 'use strict';
2
+
3
+ var chunkHZLQNKFN_cjs = require('./chunk-HZLQNKFN.cjs');
4
+
5
+
6
+
7
+ Object.defineProperty(exports, "isInMemorySource", {
8
+ enumerable: true,
9
+ get: function () { return chunkHZLQNKFN_cjs.isInMemorySource; }
10
+ });
11
+ Object.defineProperty(exports, "normalizeSource", {
12
+ enumerable: true,
13
+ get: function () { return chunkHZLQNKFN_cjs.normalizeSource; }
14
+ });
15
+ Object.defineProperty(exports, "sniffContainer", {
16
+ enumerable: true,
17
+ get: function () { return chunkHZLQNKFN_cjs.sniffContainer; }
18
+ });
19
+ Object.defineProperty(exports, "sniffContainerFromBytes", {
20
+ enumerable: true,
21
+ get: function () { return chunkHZLQNKFN_cjs.sniffContainerFromBytes; }
22
+ });
23
+ Object.defineProperty(exports, "sniffNormalizedSource", {
24
+ enumerable: true,
25
+ get: function () { return chunkHZLQNKFN_cjs.sniffNormalizedSource; }
26
+ });
27
+ //# sourceMappingURL=source-CN43EI7Z.cjs.map
28
+ //# sourceMappingURL=source-CN43EI7Z.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"source-SC6ZEQYR.cjs"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"source-CN43EI7Z.cjs"}
@@ -0,0 +1,3 @@
1
+ export { isInMemorySource, normalizeSource, sniffContainer, sniffContainerFromBytes, sniffNormalizedSource } from './chunk-ILKDNBSE.js';
2
+ //# sourceMappingURL=source-FFZ7TW2B.js.map
3
+ //# sourceMappingURL=source-FFZ7TW2B.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"source-ZFS4H7J3.js"}
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"source-FFZ7TW2B.js"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "avbridge",
3
- "version": "2.1.2",
3
+ "version": "2.2.1",
4
4
  "description": "Play and convert arbitrary video files in the browser. Native, remux, hybrid, fallback, and transcode — one API.",
5
5
  "license": "MIT",
6
6
  "author": "Keishi Hattori",
@@ -25,8 +25,15 @@ const NATIVE_AUDIO_CODECS = new Set<AudioCodec>([
25
25
  /**
26
26
  * Codecs no major browser plays, period. These force the WASM fallback.
27
27
  */
28
- const FALLBACK_VIDEO_CODECS = new Set<VideoCodec>(["wmv3", "vc1", "mpeg4", "rv40", "mpeg2", "mpeg1", "theora"]);
29
- const FALLBACK_AUDIO_CODECS = new Set<AudioCodec>(["wmav2", "wmapro", "ac3", "eac3"]);
28
+ const FALLBACK_VIDEO_CODECS = new Set<VideoCodec>([
29
+ "wmv3", "vc1", "mpeg4",
30
+ "rv10", "rv20", "rv30", "rv40",
31
+ "mpeg2", "mpeg1", "theora",
32
+ ]);
33
+ const FALLBACK_AUDIO_CODECS = new Set<AudioCodec>([
34
+ "wmav2", "wmapro", "ac3", "eac3",
35
+ "cook", "ra_144", "ra_288", "sipr", "atrac3",
36
+ ]);
30
37
 
31
38
  /**
32
39
  * Containers `<video>` plays directly. Anything else with otherwise-supported
package/src/player.ts CHANGED
@@ -5,6 +5,7 @@ import { Diagnostics } from "./diagnostics.js";
5
5
  import { PluginRegistry } from "./plugins/registry.js";
6
6
  import { registerBuiltins } from "./plugins/builtin.js";
7
7
  import { discoverSidecars, attachSubtitleTracks, SubtitleResourceBag } from "./subtitles/index.js";
8
+ import { dbg } from "./util/debug.js";
8
9
  import type {
9
10
  Classification,
10
11
  CreatePlayerOptions,
@@ -33,6 +34,11 @@ export class UnifiedPlayer {
33
34
  private lastProgressPosition = -1;
34
35
  private errorListener: (() => void) | null = null;
35
36
 
37
+ // Bound so we can removeEventListener in destroy(); without this the
38
+ // listener outlives the player and accumulates on elements that swap
39
+ // source (e.g. <avbridge-video>).
40
+ private endedListener: (() => void) | null = null;
41
+
36
42
  // Serializes escalation / setStrategy calls
37
43
  private switchingPromise: Promise<void> = Promise.resolve();
38
44
 
@@ -65,8 +71,14 @@ export class UnifiedPlayer {
65
71
  }
66
72
 
67
73
  private async bootstrap(): Promise<void> {
74
+ const bootstrapStart = performance.now();
68
75
  try {
69
- const ctx = await probe(this.options.source);
76
+ dbg.info("bootstrap", "start");
77
+ const ctx = await dbg.timed("probe", "probe", 3000, () => probe(this.options.source));
78
+ dbg.info("probe",
79
+ `container=${ctx.container} video=${ctx.videoTracks[0]?.codec ?? "-"} ` +
80
+ `audio=${ctx.audioTracks[0]?.codec ?? "-"} probedBy=${ctx.probedBy}`,
81
+ );
70
82
  this.diag.recordProbe(ctx);
71
83
  this.mediaContext = ctx;
72
84
 
@@ -99,6 +111,10 @@ export class UnifiedPlayer {
99
111
  const decision = this.options.initialStrategy
100
112
  ? buildInitialDecision(this.options.initialStrategy, ctx)
101
113
  : classify(ctx);
114
+ dbg.info("classify",
115
+ `strategy=${decision.strategy} class=${decision.class} reason="${decision.reason}"` +
116
+ (decision.fallbackChain ? ` fallback=${decision.fallbackChain.join("→")}` : ""),
117
+ );
102
118
  this.classification = decision;
103
119
  this.diag.recordClassification(decision);
104
120
 
@@ -110,12 +126,10 @@ export class UnifiedPlayer {
110
126
  // Try the primary strategy, falling through the chain on failure
111
127
  await this.startSession(decision.strategy, decision.reason);
112
128
 
113
- // Apply subtitles for non-canvas strategies. Awaited so fetch/parse
114
- // failures surface deterministically but per-track failures are
115
- // caught inside attachSubtitleTracks and logged via console.warn so
116
- // a single bad sidecar doesn't break bootstrap. Subtitles are not
117
- // load-bearing for playback. (Promoting this to a typed `subtitleerror`
118
- // event is a nice-to-have follow-up.)
129
+ // Apply subtitles for non-canvas strategies. Per-track failures are
130
+ // caught inside attachSubtitleTracks and logged via console.warn
131
+ // subtitles are not load-bearing, so a bad sidecar must not break
132
+ // bootstrap.
119
133
  if (this.session!.strategy !== "fallback" && this.session!.strategy !== "hybrid") {
120
134
  await attachSubtitleTracks(
121
135
  this.options.target,
@@ -135,8 +149,19 @@ export class UnifiedPlayer {
135
149
  });
136
150
 
137
151
  this.startTimeupdateLoop();
138
- this.options.target.addEventListener("ended", () => this.emitter.emit("ended", undefined));
152
+ this.endedListener = () => this.emitter.emit("ended", undefined);
153
+ this.options.target.addEventListener("ended", this.endedListener);
139
154
  this.emitter.emitSticky("ready", undefined);
155
+ const bootstrapElapsed = performance.now() - bootstrapStart;
156
+ dbg.info("bootstrap", `ready in ${bootstrapElapsed.toFixed(0)}ms`);
157
+ if (bootstrapElapsed > 5000) {
158
+ // eslint-disable-next-line no-console
159
+ console.warn(
160
+ "[avbridge:bootstrap]",
161
+ `total bootstrap time ${bootstrapElapsed.toFixed(0)}ms — unusually slow. ` +
162
+ `Enable globalThis.AVBRIDGE_DEBUG for a per-phase breakdown.`,
163
+ );
164
+ }
140
165
  } catch (err) {
141
166
  const e = err instanceof Error ? err : new Error(String(err));
142
167
  this.diag.recordError(e);
@@ -471,6 +496,10 @@ export class UnifiedPlayer {
471
496
  this.timeupdateInterval = null;
472
497
  }
473
498
  this.clearSupervisor();
499
+ if (this.endedListener) {
500
+ this.options.target.removeEventListener("ended", this.endedListener);
501
+ this.endedListener = null;
502
+ }
474
503
  if (this.session) {
475
504
  await this.session.destroy();
476
505
  this.session = null;
@@ -487,14 +516,12 @@ export async function createPlayer(options: CreatePlayerOptions): Promise<Unifie
487
516
  }
488
517
 
489
518
  /**
490
- * Build a synthetic classification when the consumer asked for a specific
491
- * initial strategy. We ask `classify()` for the natural decision so we can
492
- * inherit the correct fallback chain, then override the strategy + class.
493
- *
494
- * Why this matters: hard-coding `class: "NATIVE"` (the old behavior) made
495
- * diagnostics lie for every initialStrategy that wasn't actually native, and
496
- * any downstream logic that trusted `strategyClass` could make the wrong
497
- * decision. We now derive the class from the picked strategy.
519
+ * Build a synthetic classification for an explicit `initialStrategy` override.
520
+ * The `class` is derived from the chosen strategy so diagnostics and any
521
+ * downstream consumer of `strategyClass` see the real strategy. The fallback
522
+ * chain is inherited from the natural classification but must never contain
523
+ * `initial` itself otherwise `startSession` would retry the strategy that
524
+ * just failed before escalating.
498
525
  *
499
526
  * @internal — exported for unit tests; not part of the public API.
500
527
  */
@@ -504,11 +531,13 @@ export function buildInitialDecision(
504
531
  ): Classification {
505
532
  const natural = classify(ctx);
506
533
  const cls = strategyToClass(initial, natural);
534
+ const inherited = natural.fallbackChain ?? defaultFallbackChain(initial);
535
+ const fallbackChain = inherited.filter((s) => s !== initial);
507
536
  return {
508
537
  class: cls,
509
538
  strategy: initial,
510
539
  reason: `initial strategy "${initial}" requested via options.initialStrategy`,
511
- fallbackChain: natural.fallbackChain ?? defaultFallbackChain(initial),
540
+ fallbackChain,
512
541
  };
513
542
  }
514
543
 
package/src/probe/avi.ts CHANGED
@@ -177,7 +177,9 @@ function ffmpegToAvbridgeVideo(name: string): VideoCodec {
177
177
  case "mpeg2video": return "mpeg2";
178
178
  case "mpeg1video": return "mpeg1";
179
179
  case "theora": return "theora";
180
- case "rv30":
180
+ case "rv10": return "rv10";
181
+ case "rv20": return "rv20";
182
+ case "rv30": return "rv30";
181
183
  case "rv40": return "rv40";
182
184
  default: return name as VideoCodec;
183
185
  }
@@ -198,6 +200,11 @@ function ffmpegToAvbridgeAudio(name: string): AudioCodec {
198
200
  case "wmav2": return "wmav2";
199
201
  case "wmapro": return "wmapro";
200
202
  case "alac": return "alac";
203
+ case "cook": return "cook";
204
+ case "ra_144": return "ra_144";
205
+ case "ra_288": return "ra_288";
206
+ case "sipr": return "sipr";
207
+ case "atrac3": return "atrac3";
201
208
  default: return name as AudioCodec;
202
209
  }
203
210
  }
@@ -172,9 +172,31 @@ export class AudioOutput implements ClockSource {
172
172
  node.connect(this.gain);
173
173
 
174
174
  // Convert media time → ctx time using the anchor.
175
- const ctxStart = this.ctxTimeAtAnchor + (this.mediaTimeOfNext - this.mediaTimeOfAnchor);
176
- const safeStart = Math.max(ctxStart, this.ctx.currentTime);
177
- node.start(safeStart);
175
+ let ctxStart = this.ctxTimeAtAnchor + (this.mediaTimeOfNext - this.mediaTimeOfAnchor);
176
+
177
+ // When the decoder is slower than realtime, `ctxStart` falls into
178
+ // the past (ctx.currentTime has already passed it). Clamping each
179
+ // sample to `ctx.currentTime` individually (the old behavior)
180
+ // caused every stale sample in a burst to start at *the same
181
+ // instant*, stacking them on top of each other — the audible
182
+ // symptom was a series of clicks / a chord of stuttering cook
183
+ // packets.
184
+ //
185
+ // Correct behavior: when the first sample of a burst is behind,
186
+ // *rebase the anchor forward* so ctxStart = ctx.currentTime now.
187
+ // Subsequent samples in the same burst then schedule at
188
+ // ctxStart + offset as usual, laying out sequentially on the
189
+ // timeline instead of piling up. The downside is a visible jump
190
+ // in the audio clock — but the alternative was silent corruption.
191
+ // `now()` readers (the video renderer) just see the clock step
192
+ // forward and drop any frames older than the new time.
193
+ if (ctxStart < this.ctx.currentTime) {
194
+ this.ctxTimeAtAnchor = this.ctx.currentTime;
195
+ this.mediaTimeOfAnchor = this.mediaTimeOfNext;
196
+ ctxStart = this.ctx.currentTime;
197
+ }
198
+
199
+ node.start(ctxStart);
178
200
 
179
201
  this.mediaTimeOfNext += frameCount / sampleRate;
180
202
  this.framesScheduled++;