@banou/media-player 0.8.6 → 0.8.7

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.
@@ -1,2 +1,2 @@
1
- import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c, u as l } from "../engine--OlGG-Ve.js";
1
+ import { a as e, c as t, i as n, l as r, n as i, o as a, r as o, s, t as c, u as l } from "../engine-B6flRjLd.js";
2
2
  export { n as DEFAULT_BUFFER_SIZE, s as SUBTITLES_OFF, c as createPictureInPicture, t as createSubtitleRenderer, o as createThumbnailGenerator, r as getTimeRanges, i as pictureInPictureMode, e as startPlayback, a as terminateRemuxer, l as updateSourceBuffer };
@@ -168,7 +168,7 @@ var a = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
168
168
  clearTimeout(n), t.terminate();
169
169
  });
170
170
  }, T = async (t) => {
171
- let { videoElement: n, canvasElement: r, read: i, length: o, publicPath: c, libavWorkerUrl: l, jassubWorkerUrl: u, jassubWasmUrl: d, jassubLegacyWasmUrl: f, defaultFontUrl: p, bufferSize: T = C, audioStreamIndex: E, onReady: D, onError: O, onRecovered: k, onSeek: A, onSubtitleStreams: j, onAudioStreams: M } = t, N = await e({
171
+ let { videoElement: n, canvasElement: r, read: i, length: o, publicPath: c, libavWorkerUrl: l, jassubWorkerUrl: u, jassubWasmUrl: d, jassubLegacyWasmUrl: f, defaultFontUrl: p, bufferSize: T = C, audioStreamIndex: E, onReady: D, onError: O, onRecovered: k, onSeek: A, onSubtitleStreams: j, onAudioStreams: ee } = t, M = await e({
172
172
  publicPath: c,
173
173
  workerUrl: l,
174
174
  workerOptions: { type: "module" },
@@ -176,18 +176,18 @@ var a = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
176
176
  length: o,
177
177
  audioStreamIndex: E,
178
178
  read: i
179
- }), P = [], F = !1, I = () => {
180
- if (!F) {
181
- F = !0;
182
- for (let e of [...P].reverse()) try {
179
+ }), N = [], P = !1, F = () => {
180
+ if (!P) {
181
+ P = !0;
182
+ for (let e of [...N].reverse()) try {
183
183
  e();
184
184
  } catch {}
185
185
  }
186
186
  };
187
- P.push(() => w(N));
187
+ N.push(() => w(M));
188
188
  try {
189
- let e = await N.init(), t = e.audioStreams ?? [], i = t.some((e) => e.streamIndex === E) ? E : t[0]?.streamIndex ?? -1;
190
- M?.(t, i);
189
+ let e = await M.init(), t = e.audioStreams ?? [], i = t.some((e) => e.streamIndex === E) ? E : t[0]?.streamIndex ?? -1;
190
+ ee?.(t, i);
191
191
  let o = m({
192
192
  video: n,
193
193
  canvas: r,
@@ -197,11 +197,11 @@ var a = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
197
197
  defaultFontUrl: p,
198
198
  onStreams: j
199
199
  });
200
- if (P.push(() => o.destroy()), e.attachments?.length && o.pushAttachments(e.attachments), !e.info.output.videoMimeType) throw Error("The video codec in this file could not be identified");
200
+ if (N.push(() => o.destroy()), e.attachments?.length && o.pushAttachments(e.attachments), !e.info.output.videoMimeType) throw Error("The video codec in this file could not be identified");
201
201
  let c = [e.info.output.videoMimeType, e.info.output.audioMimeType].filter(Boolean).join(","), l = `video/mp4; codecs="${c}"`;
202
202
  if (!MediaSource.isTypeSupported(l)) throw Error(`This browser cannot play the codecs in this file: ${c}`);
203
203
  let C = new MediaSource(), w = URL.createObjectURL(C);
204
- P.push(() => URL.revokeObjectURL(w)), n.src = w;
204
+ N.push(() => URL.revokeObjectURL(w)), n.src = w;
205
205
  let T = await new Promise((t, n) => {
206
206
  let r = setTimeout(() => {
207
207
  i(), n(/* @__PURE__ */ Error("The MediaSource never opened"));
@@ -220,85 +220,92 @@ var a = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
220
220
  i(), n(/* @__PURE__ */ Error("The MediaSource closed before a SourceBuffer could be created"));
221
221
  };
222
222
  C.addEventListener("sourceopen", a, { once: !0 }), C.addEventListener("sourceclose", o, { once: !0 }), C.addEventListener("error", o, { once: !0 });
223
- }), { appendBuffer: L, unbufferRange: R, updateTimestampOffset: z, endOfStream: B } = s(T, C);
224
- await L(e.data), e.subtitles?.length && o.pushFragments(e.subtitles), D?.();
225
- let V = !1, H = !1, U = !1, W = 0, G = 0, K = null, q = 0, J = 0, Y = !1, X = 0, Z = (e, t) => {
223
+ }), { appendBuffer: I, unbufferRange: L, updateTimestampOffset: R, endOfStream: z } = s(T, C);
224
+ await I(e.data), e.subtitles?.length && o.pushFragments(e.subtitles), D?.();
225
+ let B = !1, V = !1, H = !1, U = 0, W = 0, G = null, K = 0, q = 0, J = !1, te = 0, Y = (e, t) => {
226
226
  let n = e?.message === "Cancelled";
227
- t && n || (console.error(e), !Y && (Y = !0, O?.(n ? Error("Reading the video file failed", { cause: e }) : e)));
228
- }, Q = async (e = !1) => {
227
+ t && n || (console.error(e), !J && (J = !0, O?.(n ? Error("Reading the video file failed", { cause: e }) : e)));
228
+ }, X = async (e = !1) => {
229
229
  let t = n.currentTime, r = e ? v : h, i = e ? y : g;
230
- for (let { start: e, end: n } of a(T)) e < t + r && await R(e, t + r), n > t + i && await R(t + i, n);
231
- }, ee = () => {
230
+ for (let { start: e, end: n } of a(T)) e < t + r && await L(e, t + r), n > t + i && await L(t + i, n);
231
+ }, ne = () => {
232
232
  let e = a(T);
233
233
  if (!e.length) return !0;
234
234
  let t = n.currentTime;
235
235
  if (Math.max(...e.map((e) => e.end)) >= t + g) return !1;
236
236
  let r = e.find((e) => e.start <= t + S && t < e.end);
237
237
  return !r || r.end < t + _;
238
- }, $ = () => {
238
+ }, Z = () => {
239
239
  let e = n.currentTime;
240
240
  return a(T).find((t) => t.start <= e + S && e < t.end);
241
- }, te = () => {
242
- let e = $();
243
- return !!e && e.end >= J - .1;
244
- }, ne = () => {
241
+ }, re = () => {
242
+ let e = Z();
243
+ return !!e && e.end >= q - .1;
244
+ }, Q = () => {
245
245
  let e = a(T).map((e) => e.end);
246
- e.length && (J = Math.max(J, ...e));
247
- }, re = async (e) => {
248
- H = !0, K = null, q = 0, X = e;
249
- let t = ++G;
246
+ e.length && (q = Math.max(q, ...e));
247
+ }, ie = async (e) => {
248
+ V = !0, G = null, K = 0, te = e;
249
+ let t = ++W;
250
250
  try {
251
- let { data: n, pts: r, subtitles: i } = await N.seek(e);
252
- if (F || t !== G || (i?.length && o.pushFragments(i), await z(r), F || t !== G)) return;
253
- n.byteLength && (await L(n), ne());
251
+ let { data: n, pts: r, subtitles: i } = await M.seek(e);
252
+ if (P || t !== W || (i?.length && o.pushFragments(i), await R(r), P || t !== W)) return;
253
+ n.byteLength && (await I(n), Q());
254
254
  } catch (e) {
255
- Z(e, F || t !== G);
255
+ Y(e, P || t !== W);
256
256
  } finally {
257
- t === G && (H = !1);
257
+ t === W && (V = !1);
258
258
  }
259
- }, ie = async () => {
260
- let e = K;
259
+ }, ae = async () => {
260
+ let e = G;
261
261
  if (e) try {
262
- await L(e), ne(), K === e && (K = null, q = 0);
262
+ await I(e), Q(), G === e && (G = null, K = 0);
263
263
  } catch (t) {
264
- if (K !== e) return;
264
+ if (G !== e) return;
265
265
  if (t?.name === "QuotaExceededError") {
266
- let t = await Q(!0).then(() => !0, () => !1);
267
- if (K !== e) return;
266
+ let t = await X(!0).then(() => !0, () => !1);
267
+ if (G !== e) return;
268
268
  if (t) {
269
- U = !1, await re($()?.end ?? n.currentTime);
269
+ H = !1, await ie(Z()?.end ?? n.currentTime);
270
270
  return;
271
271
  }
272
272
  }
273
- if (q += 1, q < b) return;
274
- throw K = null, t;
273
+ if (K += 1, K < b) return;
274
+ throw G = null, t;
275
275
  }
276
- }, ae = async () => {
277
- if (V || H || F || !K && (U || !ee())) return;
278
- let e = ++W, t = G, n = () => F || e !== W || t !== G;
279
- V = !0;
276
+ }, oe = async () => {
277
+ if (B || V || P || !G && (H || !ne())) return;
278
+ let e = ++U, t = W, n = () => P || e !== U || t !== W;
279
+ B = !0;
280
280
  try {
281
- if (!K) {
282
- let { data: e, subtitles: t, finished: r } = await N.read();
283
- if (n() || (r && (U = !0), t?.length && o.pushFragments(t), !e.byteLength)) return;
284
- K = e, q = 0;
281
+ if (!G) {
282
+ let { data: e, subtitles: t, finished: r } = await M.read();
283
+ if (n() || (r && (H = !0), t?.length && o.pushFragments(t), !e.byteLength)) return;
284
+ G = e, K = 0;
285
285
  }
286
- await ie(), !n() && Y && (Y = !1, k?.());
286
+ await ae(), !n() && J && (J = !1, k?.());
287
287
  } catch (e) {
288
- Z(e, n());
288
+ Y(e, n());
289
289
  } finally {
290
- e === W && (V = !1);
290
+ e === U && (B = !1);
291
291
  }
292
- }, oe = (e) => e >= X && !!$(), se = () => {
292
+ }, se = (e) => e >= te && !!Z(), ce = () => {
293
293
  let t = n.currentTime, r = e.info.input.duration || n.duration;
294
- r > 0 && A?.(Math.min(Math.max(t / r, 0), 1)), !oe(t) && (U = !1, re(t));
294
+ r > 0 && A?.(Math.min(Math.max(t / r, 0), 1)), !se(t) && (H = !1, ie(t));
295
+ };
296
+ n.addEventListener("seeking", ce), N.push(() => n.removeEventListener("seeking", ce));
297
+ let $ = !1, le = () => {
298
+ if ($) return;
299
+ $ = !0;
300
+ let e = n.error;
301
+ Y(Error(`the media element failed: ${e?.message ?? "unknown"}`, { cause: e }), !1);
295
302
  };
296
- n.addEventListener("seeking", se), P.push(() => n.removeEventListener("seeking", se));
297
- let ce = setInterval(() => {
298
- Q().catch(() => {}), ae().catch((e) => Z(e, !1)), U && !K && te() && C.readyState === "open" && B().catch(() => {});
303
+ n.addEventListener("error", le), N.push(() => n.removeEventListener("error", le));
304
+ let ue = setInterval(() => {
305
+ $ || n.error || (X().catch(() => {}), oe().catch((e) => Y(e, !1)), H && !G && re() && C.readyState === "open" && z().catch(() => {}));
299
306
  }, 100);
300
- return P.push(() => clearInterval(ce)), {
301
- destroy: I,
307
+ return N.push(() => clearInterval(ue)), {
308
+ destroy: F,
302
309
  selectSubtitleStream: (e) => o.selectStream(e),
303
310
  indexes: e.indexes ?? [],
304
311
  duration: e.info.input.duration,
@@ -306,9 +313,9 @@ var a = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
306
313
  audioMimeType: e.info.output.audioMimeType
307
314
  };
308
315
  } catch (e) {
309
- throw I(), e;
316
+ throw F(), e;
310
317
  }
311
- }, E = 5, D = 500, O = 320, k = 1e6, A = 3, j = 1e4, M = async (e) => {
318
+ }, E = 5, D = 500, O = 320, k = 1e6, A = 3, j = 1e4, ee = async (e) => {
312
319
  let { publicPath: n, workerUrl: r, length: i, read: a, onThumbnails: o, width: s = O } = e, c = await t({
313
320
  publicPath: n,
314
321
  workerUrl: r,
@@ -383,8 +390,8 @@ var a = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
383
390
  } catch (e) {
384
391
  throw w(c), e;
385
392
  }
386
- }, N = 1280, P = 1920, F = 250, I = 100, L = () => typeof HTMLCanvasElement < "u" && "captureStream" in HTMLCanvasElement.prototype, R = () => typeof document < "u" && typeof HTMLVideoElement < "u" && typeof HTMLVideoElement.prototype.requestPictureInPicture == "function" && !!document.pictureInPictureEnabled, z = () => typeof HTMLVideoElement < "u" && "mozCaptureStream" in HTMLVideoElement.prototype, B = () => L() ? R() ? "window" : z() ? "burn-in" : null : null, V = (e) => {
387
- let { video: t, canvas: n } = e, r = e.mode ?? B() ?? "window", i = e.maxWidth ?? (r === "burn-in" ? P : N), a, o, s, c = !1, l = !1, u = !1, d = !1, f, p = () => r === "burn-in" ? !!a : !!a && document.pictureInPictureElement === a.mirror, m = (e, r) => {
393
+ }, M = 1280, N = 1920, P = 250, F = 100, I = () => typeof HTMLCanvasElement < "u" && "captureStream" in HTMLCanvasElement.prototype, L = () => typeof document < "u" && typeof HTMLVideoElement < "u" && typeof HTMLVideoElement.prototype.requestPictureInPicture == "function" && !!document.pictureInPictureEnabled, R = () => typeof HTMLVideoElement < "u" && "mozCaptureStream" in HTMLVideoElement.prototype, z = () => I() ? L() ? "window" : R() ? "burn-in" : null : null, B = (e) => {
394
+ let { video: t, canvas: n } = e, r = e.mode ?? z() ?? "window", i = e.maxWidth ?? (r === "burn-in" ? N : M), a, o, s, c = !1, l = !1, u = !1, d = !1, f, p = () => r === "burn-in" ? !!a : !!a && document.pictureInPictureElement === a.mirror, m = (e, r) => {
388
395
  r.drawImage(t, 0, 0, e.width, e.height), n.width > 0 && n.height > 0 && r.drawImage(n, 0, 0, e.width, e.height);
389
396
  }, h = () => {
390
397
  a && m(a.composite, a.context);
@@ -411,11 +418,11 @@ var a = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
411
418
  l = !0;
412
419
  let { mirror: e } = a;
413
420
  h(), e.play().then(() => new Promise((e) => {
414
- setTimeout(e, I);
421
+ setTimeout(e, F);
415
422
  })).catch(() => {}).finally(() => {
416
423
  e.pause(), setTimeout(() => {
417
424
  l = !1;
418
- }, I);
425
+ }, F);
419
426
  });
420
427
  }, E = [["play", () => {
421
428
  t.play().catch(() => {});
@@ -452,7 +459,7 @@ var a = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
452
459
  };
453
460
  if (a = f, u.srcObject = f.stream, (e.container ?? t.parentElement ?? document.body).appendChild(u), v(), s = setInterval(() => {
454
461
  t.paused && h();
455
- }, F), u.play().catch(() => {}), u.readyState === 0 && await new Promise((e) => {
462
+ }, P), u.play().catch(() => {}), u.readyState === 0 && await new Promise((e) => {
456
463
  let t = () => {
457
464
  clearTimeout(n), e();
458
465
  }, n = setTimeout(t, 1e3);
@@ -498,4 +505,4 @@ var a = (e) => Array(e.buffered.length).fill(void 0).map((t, n) => ({
498
505
  };
499
506
  };
500
507
  //#endregion
501
- export { T as a, m as c, C as i, a as l, B as n, w as o, M as r, c as s, V as t, s as u };
508
+ export { T as a, m as c, C as i, a as l, z as n, w as o, ee as r, c as s, B as t, s as u };
package/dist/index.js CHANGED
@@ -1,4 +1,4 @@
1
- import { a as e, c as t, n, r, s as i, t as a } from "./engine--OlGG-Ve.js";
1
+ import { a as e, c as t, n, r, s as i, t as a } from "./engine-B6flRjLd.js";
2
2
  import { Children as o, Fragment as s, isValidElement as c, useCallback as l, useEffect as u, useMemo as d, useRef as f, useState as p } from "react";
3
3
  import { css as m, keyframes as h } from "@emotion/react";
4
4
  import { createPlayer as g, useContainerAttach as _, useMediaAttach as v } from "@videojs/react";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@banou/media-player",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "A video player for containers and codecs the browser cannot play natively, remuxed on the fly",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -329,7 +329,35 @@ export const startPlayback = async (options: PlaybackOptions): Promise<PlaybackC
329
329
  videoElement.addEventListener('seeking', onSeeking)
330
330
  teardown.push(() => videoElement.removeEventListener('seeking', onSeeking))
331
331
 
332
+ /**
333
+ * A terminal failure of the media element, which NOTHING here used to observe.
334
+ *
335
+ * `MediaError` is set once and the element never plays again, but the pump below kept running,
336
+ * and every `appendBuffer` after it throws `InvalidStateError: The HTMLMediaElement.error
337
+ * attribute is not null`. `updateSourceBuffer`'s chain deliberately survives a rejection, so that
338
+ * repeated forever, and `flushPending` swallows four attempts and rethrows the fifth. What
339
+ * reached the viewer was therefore the FIFTH `InvalidStateError` rather than the real cause, and
340
+ * the real cause never appeared anywhere at all.
341
+ *
342
+ * That cost a session: a decode failure presented as an append bug, which is a completely
343
+ * different place to look. Report what actually happened, then stop.
344
+ */
345
+ let elementFailed = false
346
+ const onElementError = () => {
347
+ if (elementFailed) return
348
+ elementFailed = true
349
+ const error = videoElement.error
350
+ reportError(
351
+ new Error(`the media element failed: ${error?.message ?? 'unknown'}`, { cause: error }),
352
+ false,
353
+ )
354
+ }
355
+ videoElement.addEventListener('error', onElementError)
356
+ teardown.push(() => videoElement.removeEventListener('error', onElementError))
357
+
332
358
  const interval = setInterval(() => {
359
+ // Nothing below can succeed against a failed element, and retrying only buries the real error.
360
+ if (elementFailed || videoElement.error) return
333
361
  evict().catch(() => {})
334
362
  pump().catch((error) => reportError(error, false))
335
363
  // every remove() puts the MediaSource back to 'open', so the end has to be re-armed