avbridge 2.8.4 → 2.9.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 +133 -0
- package/README.md +74 -1
- package/dist/{avi-F6WZJK5T.cjs → avi-2ILLBNPQ.cjs} +8 -2
- package/dist/avi-2ILLBNPQ.cjs.map +1 -0
- package/dist/{avi-W6L3BTWU.cjs → avi-B5CQYB7L.cjs} +8 -2
- package/dist/avi-B5CQYB7L.cjs.map +1 -0
- package/dist/{avi-2JPBSHGA.js → avi-JXU4GQL2.js} +8 -2
- package/dist/avi-JXU4GQL2.js.map +1 -0
- package/dist/{avi-NJXAXUXK.js → avi-RWWPN2PR.js} +8 -2
- package/dist/avi-RWWPN2PR.js.map +1 -0
- package/dist/{chunk-X2K3GIWE.js → chunk-2NSOOMXW.js} +14 -3
- package/dist/chunk-2NSOOMXW.js.map +1 -0
- package/dist/{chunk-ZCUXHW55.cjs → chunk-BYGZN4Z5.cjs} +5 -5
- package/dist/{chunk-ZCUXHW55.cjs.map → chunk-BYGZN4Z5.cjs.map} +1 -1
- package/dist/{chunk-SMH6IOP2.js → chunk-CL6UEUQF.js} +4 -4
- package/dist/{chunk-SMH6IOP2.js.map → chunk-CL6UEUQF.js.map} +1 -1
- package/dist/{chunk-YX4AGLNF.cjs → chunk-EY6DZEDT.cjs} +89 -15
- package/dist/chunk-EY6DZEDT.cjs.map +1 -0
- package/dist/{chunk-SR3MPV4D.js → chunk-GYIJU44C.js} +5 -5
- package/dist/{chunk-SR3MPV4D.js.map → chunk-GYIJU44C.js.map} +1 -1
- package/dist/{chunk-CPZ7PXAM.cjs → chunk-L7A3ECI2.cjs} +14 -2
- package/dist/chunk-L7A3ECI2.cjs.map +1 -0
- package/dist/{chunk-Q2VUO52Z.cjs → chunk-OTFS7DC4.cjs} +12 -12
- package/dist/{chunk-Q2VUO52Z.cjs.map → chunk-OTFS7DC4.cjs.map} +1 -1
- package/dist/{chunk-KBWQRGHS.js → chunk-SN4WZE24.js} +79 -5
- package/dist/chunk-SN4WZE24.js.map +1 -0
- package/dist/element-browser.js +104 -7
- package/dist/element-browser.js.map +1 -1
- package/dist/element.cjs +16 -10
- package/dist/element.cjs.map +1 -1
- package/dist/element.d.cts +11 -6
- package/dist/element.d.ts +11 -6
- package/dist/element.js +15 -9
- package/dist/element.js.map +1 -1
- package/dist/index.cjs +20 -20
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +8 -8
- package/dist/libav-demux-3N5Y3VQA.cjs +31 -0
- package/dist/{libav-demux-H2GS46GH.cjs.map → libav-demux-3N5Y3VQA.cjs.map} +1 -1
- package/dist/libav-demux-JXD4OTLM.js +6 -0
- package/dist/{libav-demux-OWZ4T2YW.js.map → libav-demux-JXD4OTLM.js.map} +1 -1
- package/dist/{player-BptSJPfn.d.cts → player-DEcidWk6.d.cts} +1 -1
- package/dist/{player-BptSJPfn.d.ts → player-DEcidWk6.d.ts} +1 -1
- package/dist/player.cjs +187 -23
- package/dist/player.cjs.map +1 -1
- package/dist/player.d.cts +17 -11
- package/dist/player.d.ts +17 -11
- package/dist/player.js +187 -23
- package/dist/player.js.map +1 -1
- package/dist/{remux-WBYIZBBX.js → remux-56V7LDAD.js} +5 -5
- package/dist/{remux-WBYIZBBX.js.map → remux-56V7LDAD.js.map} +1 -1
- package/dist/{remux-OBSMIENG.cjs → remux-KUS5GIL6.cjs} +10 -10
- package/dist/{remux-OBSMIENG.cjs.map → remux-KUS5GIL6.cjs.map} +1 -1
- package/package.json +1 -1
- package/src/classify/rules.ts +2 -0
- package/src/element/avbridge-player.ts +22 -11
- package/src/element/avbridge-video.ts +22 -6
- package/src/element/player-styles.ts +68 -3
- package/src/probe/avi.ts +2 -0
- package/src/strategies/fallback/decoder.ts +30 -0
- package/src/strategies/fallback/index.ts +30 -0
- package/src/strategies/hybrid/decoder.ts +35 -0
- package/src/strategies/hybrid/index.ts +17 -0
- package/src/strategies/remux/index.ts +8 -0
- package/src/types.ts +6 -0
- package/src/util/libav-demux.ts +26 -0
- package/dist/avi-2JPBSHGA.js.map +0 -1
- package/dist/avi-F6WZJK5T.cjs.map +0 -1
- package/dist/avi-NJXAXUXK.js.map +0 -1
- package/dist/avi-W6L3BTWU.cjs.map +0 -1
- package/dist/chunk-CPZ7PXAM.cjs.map +0 -1
- package/dist/chunk-KBWQRGHS.js.map +0 -1
- package/dist/chunk-X2K3GIWE.js.map +0 -1
- package/dist/chunk-YX4AGLNF.cjs.map +0 -1
- package/dist/libav-demux-H2GS46GH.cjs +0 -27
- package/dist/libav-demux-OWZ4T2YW.js +0 -6
package/dist/element-browser.js
CHANGED
|
@@ -30030,6 +30030,12 @@ function ffmpegToAvbridgeVideo(name) {
|
|
|
30030
30030
|
return "rv30";
|
|
30031
30031
|
case "rv40":
|
|
30032
30032
|
return "rv40";
|
|
30033
|
+
case "dvvideo":
|
|
30034
|
+
return "dv";
|
|
30035
|
+
// DV / DVCPRO (camcorder, MiniDV)
|
|
30036
|
+
case "hq_hqa":
|
|
30037
|
+
return "hq_hqa";
|
|
30038
|
+
// Canopus HQ / HQA (Grass Valley)
|
|
30033
30039
|
default:
|
|
30034
30040
|
return name;
|
|
30035
30041
|
}
|
|
@@ -31564,7 +31570,13 @@ var FALLBACK_VIDEO_CODECS = /* @__PURE__ */ new Set([
|
|
|
31564
31570
|
"rv40",
|
|
31565
31571
|
"mpeg2",
|
|
31566
31572
|
"mpeg1",
|
|
31567
|
-
"theora"
|
|
31573
|
+
"theora",
|
|
31574
|
+
"dv",
|
|
31575
|
+
"hq_hqa",
|
|
31576
|
+
"rawvideo",
|
|
31577
|
+
"qtrle",
|
|
31578
|
+
"png",
|
|
31579
|
+
"vp6f"
|
|
31568
31580
|
]);
|
|
31569
31581
|
var FALLBACK_AUDIO_CODECS = /* @__PURE__ */ new Set([
|
|
31570
31582
|
"wmav2",
|
|
@@ -32401,6 +32413,12 @@ async function createRemuxSession(context, video) {
|
|
|
32401
32413
|
}
|
|
32402
32414
|
const wasPlaying = !video.paused;
|
|
32403
32415
|
await pipeline.seek(time, wasPlaying || wantPlay);
|
|
32416
|
+
queueMicrotask(() => {
|
|
32417
|
+
try {
|
|
32418
|
+
video.dispatchEvent(new Event("seeked"));
|
|
32419
|
+
} catch {
|
|
32420
|
+
}
|
|
32421
|
+
});
|
|
32404
32422
|
},
|
|
32405
32423
|
async setAudioTrack(id) {
|
|
32406
32424
|
if (!context.audioTracks.some((t) => t.id === id)) {
|
|
@@ -33042,6 +33060,17 @@ function sanitizePacketTimestamp(pkt, nextUs, fallbackTimeBase) {
|
|
|
33042
33060
|
pkt.time_base_num = 1;
|
|
33043
33061
|
pkt.time_base_den = 1e6;
|
|
33044
33062
|
}
|
|
33063
|
+
function packetPtsSec(pkt, timeBase) {
|
|
33064
|
+
const lo = pkt.pts ?? 0;
|
|
33065
|
+
const hi = pkt.ptshi ?? 0;
|
|
33066
|
+
const isInvalid = hi === -2147483648 && lo === 0 || !Number.isFinite(lo);
|
|
33067
|
+
if (isInvalid) return null;
|
|
33068
|
+
const tb = timeBase ?? [1, 1e6];
|
|
33069
|
+
if (!tb[0] || !tb[1]) return null;
|
|
33070
|
+
const pts64 = hi * 4294967296 + lo;
|
|
33071
|
+
const sec = pts64 * tb[0] / tb[1];
|
|
33072
|
+
return Number.isFinite(sec) ? sec : null;
|
|
33073
|
+
}
|
|
33045
33074
|
var AV_SAMPLE_FMT_U8 = 0;
|
|
33046
33075
|
var AV_SAMPLE_FMT_S16 = 1;
|
|
33047
33076
|
var AV_SAMPLE_FMT_S32 = 2;
|
|
@@ -33302,6 +33331,7 @@ async function startHybridDecoder(opts) {
|
|
|
33302
33331
|
let videoFramesDecoded = 0;
|
|
33303
33332
|
let audioFramesDecoded = 0;
|
|
33304
33333
|
let videoChunksFed = 0;
|
|
33334
|
+
let bufferedUntilSec = 0;
|
|
33305
33335
|
let syntheticVideoUs = 0;
|
|
33306
33336
|
let syntheticAudioUs = 0;
|
|
33307
33337
|
const videoTrackInfo = opts.context.videoTracks.find((t) => t.id === videoStream?.index);
|
|
@@ -33322,6 +33352,18 @@ async function startHybridDecoder(opts) {
|
|
|
33322
33352
|
if (myToken !== pumpToken || destroyed) return;
|
|
33323
33353
|
const videoPackets = videoStream ? packets[videoStream.index] : void 0;
|
|
33324
33354
|
const audioPackets = audioStream ? packets[audioStream.index] : void 0;
|
|
33355
|
+
if (videoPackets && videoTimeBase) {
|
|
33356
|
+
for (const pkt of videoPackets) {
|
|
33357
|
+
const sec = packetPtsSec(pkt, videoTimeBase);
|
|
33358
|
+
if (sec != null && sec > bufferedUntilSec) bufferedUntilSec = sec;
|
|
33359
|
+
}
|
|
33360
|
+
}
|
|
33361
|
+
if (audioPackets && audioTimeBase) {
|
|
33362
|
+
for (const pkt of audioPackets) {
|
|
33363
|
+
const sec = packetPtsSec(pkt, audioTimeBase);
|
|
33364
|
+
if (sec != null && sec > bufferedUntilSec) bufferedUntilSec = sec;
|
|
33365
|
+
}
|
|
33366
|
+
}
|
|
33325
33367
|
if (audioDec && audioPackets && audioPackets.length > 0) {
|
|
33326
33368
|
await decodeAudioBatch(audioPackets, myToken);
|
|
33327
33369
|
}
|
|
@@ -33578,6 +33620,9 @@ async function startHybridDecoder(opts) {
|
|
|
33578
33620
|
(err) => console.error("[avbridge] hybrid pump failed (post-seek):", err)
|
|
33579
33621
|
);
|
|
33580
33622
|
},
|
|
33623
|
+
bufferedUntilSec() {
|
|
33624
|
+
return bufferedUntilSec;
|
|
33625
|
+
},
|
|
33581
33626
|
stats() {
|
|
33582
33627
|
return {
|
|
33583
33628
|
decoderType: "webcodecs-hybrid",
|
|
@@ -33705,6 +33750,13 @@ async function createHybridSession(ctx, target, transport) {
|
|
|
33705
33750
|
configurable: true,
|
|
33706
33751
|
get: () => makeTimeRanges(ctx.duration && Number.isFinite(ctx.duration) && ctx.duration > 0 ? [[0, ctx.duration]] : [])
|
|
33707
33752
|
});
|
|
33753
|
+
Object.defineProperty(target, "buffered", {
|
|
33754
|
+
configurable: true,
|
|
33755
|
+
get: () => {
|
|
33756
|
+
const end = handles.bufferedUntilSec();
|
|
33757
|
+
return makeTimeRanges(end > 0 ? [[0, end]] : []);
|
|
33758
|
+
}
|
|
33759
|
+
});
|
|
33708
33760
|
async function waitForBuffer() {
|
|
33709
33761
|
const start = performance.now();
|
|
33710
33762
|
while (true) {
|
|
@@ -33718,6 +33770,7 @@ async function createHybridSession(ctx, target, transport) {
|
|
|
33718
33770
|
}
|
|
33719
33771
|
async function doSeek(timeSec) {
|
|
33720
33772
|
const wasPlaying = audio.isPlaying();
|
|
33773
|
+
target.dispatchEvent(new Event("seeking"));
|
|
33721
33774
|
await audio.pause().catch(() => {
|
|
33722
33775
|
});
|
|
33723
33776
|
await handles.seek(timeSec).catch(
|
|
@@ -33729,7 +33782,14 @@ async function createHybridSession(ctx, target, transport) {
|
|
|
33729
33782
|
await waitForBuffer();
|
|
33730
33783
|
await audio.start();
|
|
33731
33784
|
}
|
|
33785
|
+
target.dispatchEvent(new Event("seeked"));
|
|
33732
33786
|
}
|
|
33787
|
+
queueMicrotask(() => {
|
|
33788
|
+
try {
|
|
33789
|
+
target.dispatchEvent(new Event("loadedmetadata"));
|
|
33790
|
+
} catch {
|
|
33791
|
+
}
|
|
33792
|
+
});
|
|
33733
33793
|
let fatalErrorHandler = null;
|
|
33734
33794
|
handles.onFatalError((reason) => fatalErrorHandler?.(reason));
|
|
33735
33795
|
return {
|
|
@@ -33916,6 +33976,7 @@ async function startDecoder(opts) {
|
|
|
33916
33976
|
let pumpRunning = null;
|
|
33917
33977
|
let packetsRead = 0;
|
|
33918
33978
|
let videoFramesDecoded = 0;
|
|
33979
|
+
let bufferedUntilSec = 0;
|
|
33919
33980
|
let audioFramesDecoded = 0;
|
|
33920
33981
|
let watchdogFirstFrameMs = 0;
|
|
33921
33982
|
let watchdogSlowSinceMs = 0;
|
|
@@ -33941,6 +34002,18 @@ async function startDecoder(opts) {
|
|
|
33941
34002
|
if (myToken !== pumpToken || destroyed) return;
|
|
33942
34003
|
const videoPackets = videoStream ? packets[videoStream.index] : void 0;
|
|
33943
34004
|
const audioPackets = audioStream ? packets[audioStream.index] : void 0;
|
|
34005
|
+
if (videoPackets && videoTimeBase) {
|
|
34006
|
+
for (const pkt of videoPackets) {
|
|
34007
|
+
const sec = packetPtsSec(pkt, videoTimeBase);
|
|
34008
|
+
if (sec != null && sec > bufferedUntilSec) bufferedUntilSec = sec;
|
|
34009
|
+
}
|
|
34010
|
+
}
|
|
34011
|
+
if (audioPackets && audioTimeBase) {
|
|
34012
|
+
for (const pkt of audioPackets) {
|
|
34013
|
+
const sec = packetPtsSec(pkt, audioTimeBase);
|
|
34014
|
+
if (sec != null && sec > bufferedUntilSec) bufferedUntilSec = sec;
|
|
34015
|
+
}
|
|
34016
|
+
}
|
|
33944
34017
|
if (audioDec && audioPackets && audioPackets.length > 0) {
|
|
33945
34018
|
await decodeAudioBatch(audioPackets, myToken);
|
|
33946
34019
|
}
|
|
@@ -34222,6 +34295,9 @@ async function startDecoder(opts) {
|
|
|
34222
34295
|
(err) => console.error("[avbridge] decoder pump failed (post-seek):", err)
|
|
34223
34296
|
);
|
|
34224
34297
|
},
|
|
34298
|
+
bufferedUntilSec() {
|
|
34299
|
+
return bufferedUntilSec;
|
|
34300
|
+
},
|
|
34225
34301
|
stats() {
|
|
34226
34302
|
return {
|
|
34227
34303
|
decoderType: "libav-wasm",
|
|
@@ -34322,6 +34398,13 @@ async function createFallbackSession(ctx, target, transport) {
|
|
|
34322
34398
|
configurable: true,
|
|
34323
34399
|
get: () => makeTimeRanges(ctx.duration && Number.isFinite(ctx.duration) && ctx.duration > 0 ? [[0, ctx.duration]] : [])
|
|
34324
34400
|
});
|
|
34401
|
+
Object.defineProperty(target, "buffered", {
|
|
34402
|
+
configurable: true,
|
|
34403
|
+
get: () => {
|
|
34404
|
+
const end = handles.bufferedUntilSec();
|
|
34405
|
+
return makeTimeRanges(end > 0 ? [[0, end]] : []);
|
|
34406
|
+
}
|
|
34407
|
+
});
|
|
34325
34408
|
async function waitForBuffer() {
|
|
34326
34409
|
const start = performance.now();
|
|
34327
34410
|
let firstFrameAtMs = 0;
|
|
@@ -34361,6 +34444,7 @@ async function createFallbackSession(ctx, target, transport) {
|
|
|
34361
34444
|
}
|
|
34362
34445
|
async function doSeek(timeSec) {
|
|
34363
34446
|
const wasPlaying = audio.isPlaying();
|
|
34447
|
+
target.dispatchEvent(new Event("seeking"));
|
|
34364
34448
|
await audio.pause().catch(() => {
|
|
34365
34449
|
});
|
|
34366
34450
|
await handles.seek(timeSec).catch(
|
|
@@ -34372,7 +34456,14 @@ async function createFallbackSession(ctx, target, transport) {
|
|
|
34372
34456
|
await waitForBuffer();
|
|
34373
34457
|
await audio.start();
|
|
34374
34458
|
}
|
|
34459
|
+
target.dispatchEvent(new Event("seeked"));
|
|
34375
34460
|
}
|
|
34461
|
+
queueMicrotask(() => {
|
|
34462
|
+
try {
|
|
34463
|
+
target.dispatchEvent(new Event("loadedmetadata"));
|
|
34464
|
+
} catch {
|
|
34465
|
+
}
|
|
34466
|
+
});
|
|
34376
34467
|
return {
|
|
34377
34468
|
strategy: "fallback",
|
|
34378
34469
|
async play() {
|
|
@@ -35455,9 +35546,10 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
|
|
|
35455
35546
|
else this.removeAttribute("autoplay");
|
|
35456
35547
|
}
|
|
35457
35548
|
get muted() {
|
|
35458
|
-
return this.
|
|
35549
|
+
return this._videoEl.muted;
|
|
35459
35550
|
}
|
|
35460
35551
|
set muted(value) {
|
|
35552
|
+
this._videoEl.muted = value;
|
|
35461
35553
|
if (value) this.setAttribute("muted", "");
|
|
35462
35554
|
else this.removeAttribute("muted");
|
|
35463
35555
|
}
|
|
@@ -35522,11 +35614,16 @@ var AvbridgeVideoElement = class extends HTMLElementCtor {
|
|
|
35522
35614
|
}
|
|
35523
35615
|
/**
|
|
35524
35616
|
* Buffered time ranges for the active source. Mirrors the standard
|
|
35525
|
-
* `<video>.buffered` `TimeRanges` API.
|
|
35526
|
-
*
|
|
35527
|
-
*
|
|
35528
|
-
*
|
|
35529
|
-
*
|
|
35617
|
+
* `<video>.buffered` `TimeRanges` API.
|
|
35618
|
+
*
|
|
35619
|
+
* - **Native / remux:** pass-through to the real `<video>.buffered`
|
|
35620
|
+
* (reflects the browser's SourceBuffer / progressive-download state).
|
|
35621
|
+
* - **Hybrid / fallback:** a single `[0, frontier]` range synthesized
|
|
35622
|
+
* from the demuxer's read progress — "how far libav has ever pumped
|
|
35623
|
+
* packets through." Monotonic; does not shrink on seek. This is an
|
|
35624
|
+
* approximation, not MSE-fidelity: decoded frames on canvas strategies
|
|
35625
|
+
* are consumed in flight, so we can't report per-range availability
|
|
35626
|
+
* the way MSE does. Enough for a seek-bar buffered indicator.
|
|
35530
35627
|
*/
|
|
35531
35628
|
get buffered() {
|
|
35532
35629
|
return this._videoEl.buffered;
|