movi-player 0.3.3 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -12
- package/dist/core/MoviPlayer.d.ts +65 -1
- package/dist/core/MoviPlayer.d.ts.map +1 -1
- package/dist/core/MoviPlayer.js +245 -10
- package/dist/core/MoviPlayer.js.map +1 -1
- package/dist/decode/AudioDecoder.d.ts +4 -0
- package/dist/decode/AudioDecoder.d.ts.map +1 -1
- package/dist/decode/AudioDecoder.js +14 -0
- package/dist/decode/AudioDecoder.js.map +1 -1
- package/dist/decode/SoftwareAudioDecoder.d.ts +12 -0
- package/dist/decode/SoftwareAudioDecoder.d.ts.map +1 -1
- package/dist/decode/SoftwareAudioDecoder.js +91 -2
- package/dist/decode/SoftwareAudioDecoder.js.map +1 -1
- package/dist/decode/VideoDecoder.d.ts.map +1 -1
- package/dist/decode/VideoDecoder.js +7 -0
- package/dist/decode/VideoDecoder.js.map +1 -1
- package/dist/demuxer.cjs +1863 -1788
- package/dist/demuxer.js +1722 -1649
- package/dist/element.cjs +2987 -1933
- package/dist/element.d.ts +48 -0
- package/dist/element.d.ts.map +1 -1
- package/dist/element.js +8008 -6950
- package/dist/element.js.map +1 -1
- package/dist/index.cjs +2987 -1933
- package/dist/index.js +8008 -6950
- package/dist/player.cjs +3102 -2970
- package/dist/player.js +1812 -1680
- package/dist/render/AudioRenderer.d.ts +30 -0
- package/dist/render/AudioRenderer.d.ts.map +1 -1
- package/dist/render/AudioRenderer.js +127 -44
- package/dist/render/AudioRenderer.js.map +1 -1
- package/dist/render/CanvasRenderer.d.ts +31 -0
- package/dist/render/CanvasRenderer.d.ts.map +1 -1
- package/dist/render/CanvasRenderer.js +81 -25
- package/dist/render/CanvasRenderer.js.map +1 -1
- package/dist/render/DASHPlayerWrapper.d.ts.map +1 -1
- package/dist/render/DASHPlayerWrapper.js +3 -1
- package/dist/render/DASHPlayerWrapper.js.map +1 -1
- package/dist/render/HLSPlayerWrapper.d.ts.map +1 -1
- package/dist/render/HLSPlayerWrapper.js +3 -1
- package/dist/render/HLSPlayerWrapper.js.map +1 -1
- package/dist/render/MoviElement.d.ts +237 -0
- package/dist/render/MoviElement.d.ts.map +1 -1
- package/dist/render/MoviElement.js +2154 -232
- package/dist/render/MoviElement.js.map +1 -1
- package/dist/render/ShakaPlayerWrapper.d.ts.map +1 -1
- package/dist/render/ShakaPlayerWrapper.js +3 -1
- package/dist/render/ShakaPlayerWrapper.js.map +1 -1
- package/dist/source/HttpSource.d.ts +3 -0
- package/dist/source/HttpSource.d.ts.map +1 -1
- package/dist/source/HttpSource.js +81 -22
- package/dist/source/HttpSource.js.map +1 -1
- package/dist/utils/QoE.d.ts +126 -0
- package/dist/utils/QoE.d.ts.map +1 -0
- package/dist/utils/QoE.js +192 -0
- package/dist/utils/QoE.js.map +1 -0
- package/dist/utils/ThumbnailRenderer.d.ts +25 -0
- package/dist/utils/ThumbnailRenderer.d.ts.map +1 -1
- package/dist/utils/ThumbnailRenderer.js +195 -2
- package/dist/utils/ThumbnailRenderer.js.map +1 -1
- package/dist/wasm/bindings.d.ts +8 -0
- package/dist/wasm/bindings.d.ts.map +1 -1
- package/dist/wasm/bindings.js +31 -7
- package/dist/wasm/bindings.js.map +1 -1
- package/dist/wasm/movi.js +0 -0
- package/package.json +3 -2
|
@@ -867,6 +867,37 @@ export class CanvasRenderer {
|
|
|
867
867
|
isVR360Enabled() {
|
|
868
868
|
return this.vr360Enabled;
|
|
869
869
|
}
|
|
870
|
+
/**
|
|
871
|
+
* The currently-displayed decoded VideoFrame (or null). Used as a fallback
|
|
872
|
+
* capture source when reading the WebGL canvas back via toDataURL comes out
|
|
873
|
+
* blank — some GPUs return an all-black buffer for hardware-decoded frames
|
|
874
|
+
* even with preserveDrawingBuffer. The frame is owned by the renderer and may
|
|
875
|
+
* be closed on the next present, so consume it synchronously.
|
|
876
|
+
*/
|
|
877
|
+
getCurrentFrame() {
|
|
878
|
+
return this.lastRenderedFrame;
|
|
879
|
+
}
|
|
880
|
+
/**
|
|
881
|
+
* Snapshot the live 360° camera + projection so a thumbnail/preview can be
|
|
882
|
+
* reprojected to exactly what the user currently sees. Returns the CURRENT
|
|
883
|
+
* (rendered, post-spring) yaw/pitch/fov — i.e. the on-screen view, not the
|
|
884
|
+
* drag target. Null when 360 is off.
|
|
885
|
+
*/
|
|
886
|
+
getVRView() {
|
|
887
|
+
if (!this.vr360Enabled)
|
|
888
|
+
return null;
|
|
889
|
+
return {
|
|
890
|
+
yaw: this.vrYaw,
|
|
891
|
+
pitch: this.vrPitch,
|
|
892
|
+
fov: this.vrFov,
|
|
893
|
+
aspect: this.height > 0 ? this.width / this.height : 16 / 9,
|
|
894
|
+
half: this.vrHalf,
|
|
895
|
+
fisheye: this.vrFisheye,
|
|
896
|
+
sbs: this.vrStereoSbs,
|
|
897
|
+
stereographic: this.vrStereographic,
|
|
898
|
+
texAspect: this.vrTexAspect,
|
|
899
|
+
};
|
|
900
|
+
}
|
|
870
901
|
/** Choose the VR projection/layout:
|
|
871
902
|
* - half: false = full 360° equirectangular, true = front-hemisphere (VR180).
|
|
872
903
|
* - fisheye: true = equidistant fisheye instead of equirectangular.
|
|
@@ -1282,20 +1313,26 @@ export class CanvasRenderer {
|
|
|
1282
1313
|
}
|
|
1283
1314
|
// Update overlay dimensions
|
|
1284
1315
|
if (this.subtitleOverlay) {
|
|
1285
|
-
//
|
|
1286
|
-
//
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
//
|
|
1290
|
-
const
|
|
1316
|
+
// The overlay lives in the video's own (pre-rotation) coordinate space
|
|
1317
|
+
// and is then rotated to match the video, so captions ride the video's
|
|
1318
|
+
// bottom edge and turn with it. For 90°/270° the box is swapped (H×W)
|
|
1319
|
+
// and centred in the container so that, once rotated around its centre,
|
|
1320
|
+
// it maps back onto the video area.
|
|
1321
|
+
const rot = (((this.rotation ?? 0) % 360) + 360) % 360;
|
|
1322
|
+
const swapped = rot === 90 || rot === 270;
|
|
1323
|
+
const overlayWidth = swapped ? height : width;
|
|
1324
|
+
const overlayHeight = swapped ? width : height;
|
|
1325
|
+
// Responsive bottom padding is relative to the video's visual height
|
|
1326
|
+
// in its own frame (overlayHeight), not the container.
|
|
1327
|
+
const bottomPadding = CanvasRenderer.computeSubtitleBottomPadding(overlayHeight);
|
|
1291
1328
|
// Reset overlay positioning to ensure it stays aligned with canvas
|
|
1292
1329
|
this.subtitleOverlay.style.position = "absolute";
|
|
1293
|
-
this.subtitleOverlay.style.top = "0";
|
|
1294
|
-
this.subtitleOverlay.style.left = "0";
|
|
1295
1330
|
this.subtitleOverlay.style.right = "auto";
|
|
1296
1331
|
this.subtitleOverlay.style.bottom = "auto";
|
|
1297
|
-
this.subtitleOverlay.style.width = `${
|
|
1298
|
-
this.subtitleOverlay.style.height = `${
|
|
1332
|
+
this.subtitleOverlay.style.width = `${overlayWidth}px`;
|
|
1333
|
+
this.subtitleOverlay.style.height = `${overlayHeight}px`;
|
|
1334
|
+
this.subtitleOverlay.style.left = `${(width - overlayWidth) / 2}px`;
|
|
1335
|
+
this.subtitleOverlay.style.top = `${(height - overlayHeight) / 2}px`;
|
|
1299
1336
|
this.subtitleOverlay.style.margin = "0";
|
|
1300
1337
|
this.subtitleOverlay.style.padding = "0";
|
|
1301
1338
|
const effectivePadding = this.subtitleControlsPadding > 0 ? this.subtitleControlsPadding : bottomPadding;
|
|
@@ -1304,7 +1341,8 @@ export class CanvasRenderer {
|
|
|
1304
1341
|
this.subtitleOverlay.style.flexDirection = "column";
|
|
1305
1342
|
this.subtitleOverlay.style.justifyContent = "flex-end";
|
|
1306
1343
|
this.subtitleOverlay.style.alignItems = "center";
|
|
1307
|
-
this.subtitleOverlay.style.
|
|
1344
|
+
this.subtitleOverlay.style.transformOrigin = "center center";
|
|
1345
|
+
this.subtitleOverlay.style.transform = rot ? `rotate(${rot}deg)` : "none";
|
|
1308
1346
|
this.subtitleOverlay.style.boxSizing = "border-box";
|
|
1309
1347
|
// Schedule a re-render so the on-screen subtitle picks up the
|
|
1310
1348
|
// new dimensions. Coalesce via rAF — a window drag bursts
|
|
@@ -2352,23 +2390,31 @@ export class CanvasRenderer {
|
|
|
2352
2390
|
// Override CSS defaults that might interfere
|
|
2353
2391
|
// The overlay should cover the entire canvas area and not overflow
|
|
2354
2392
|
// Position overlay at bottom center (above controls), same as text subtitles
|
|
2393
|
+
// Rotate the overlay to match the video (same approach as text captions),
|
|
2394
|
+
// swapping to the video's own frame dimensions for 90°/270° and centring
|
|
2395
|
+
// so it maps back onto the video once rotated.
|
|
2396
|
+
const rotImg = (((this.rotation ?? 0) % 360) + 360) % 360;
|
|
2397
|
+
const swappedImg = rotImg === 90 || rotImg === 270;
|
|
2398
|
+
const ovW = swappedImg ? canvasHeight : canvasWidth;
|
|
2399
|
+
const ovH = swappedImg ? canvasWidth : canvasHeight;
|
|
2355
2400
|
this.subtitleOverlay.style.position = "absolute";
|
|
2356
|
-
this.subtitleOverlay.style.top = "0";
|
|
2357
|
-
this.subtitleOverlay.style.left = "0";
|
|
2358
2401
|
this.subtitleOverlay.style.right = "auto";
|
|
2359
2402
|
this.subtitleOverlay.style.bottom = "auto";
|
|
2360
|
-
this.subtitleOverlay.style.width = `${
|
|
2361
|
-
this.subtitleOverlay.style.height = `${
|
|
2403
|
+
this.subtitleOverlay.style.width = `${ovW}px`;
|
|
2404
|
+
this.subtitleOverlay.style.height = `${ovH}px`;
|
|
2405
|
+
this.subtitleOverlay.style.left = `${(canvasWidth - ovW) / 2}px`;
|
|
2406
|
+
this.subtitleOverlay.style.top = `${(canvasHeight - ovH) / 2}px`;
|
|
2362
2407
|
this.subtitleOverlay.style.pointerEvents = "none";
|
|
2363
2408
|
// zIndex controlled by CSS (.movi-subtitle-overlay)
|
|
2364
|
-
this.subtitleOverlay.style.
|
|
2409
|
+
this.subtitleOverlay.style.transformOrigin = "center center";
|
|
2410
|
+
this.subtitleOverlay.style.transform = rotImg ? `rotate(${rotImg}deg)` : "none";
|
|
2365
2411
|
this.subtitleOverlay.style.display = "flex";
|
|
2366
2412
|
this.subtitleOverlay.style.flexDirection = "column";
|
|
2367
2413
|
this.subtitleOverlay.style.justifyContent = "flex-end";
|
|
2368
2414
|
this.subtitleOverlay.style.alignItems = "center";
|
|
2369
2415
|
this.subtitleOverlay.style.overflow = "hidden"; // Prevent overflow outside canvas
|
|
2370
2416
|
this.subtitleOverlay.style.padding = "0";
|
|
2371
|
-
const bottomPaddingImg = CanvasRenderer.computeSubtitleBottomPadding(
|
|
2417
|
+
const bottomPaddingImg = CanvasRenderer.computeSubtitleBottomPadding(ovH);
|
|
2372
2418
|
const effectivePaddingImg = this.subtitleControlsPadding > 0 ? this.subtitleControlsPadding : bottomPaddingImg;
|
|
2373
2419
|
this.subtitleOverlay.style.paddingBottom = `${effectivePaddingImg}px`;
|
|
2374
2420
|
this.subtitleOverlay.style.textAlign = "center";
|
|
@@ -2408,8 +2454,8 @@ export class CanvasRenderer {
|
|
|
2408
2454
|
imgElement.src = dataUrl;
|
|
2409
2455
|
imgElement.style.width = `${scaledWidth}px`;
|
|
2410
2456
|
imgElement.style.height = `${scaledHeight}px`;
|
|
2411
|
-
imgElement.style.maxWidth = `${
|
|
2412
|
-
imgElement.style.maxHeight = `${
|
|
2457
|
+
imgElement.style.maxWidth = `${ovW}px`; // Ensure image doesn't exceed the (rotated) video frame width
|
|
2458
|
+
imgElement.style.maxHeight = `${ovH}px`; // Ensure image doesn't exceed the (rotated) video frame height
|
|
2413
2459
|
imgElement.style.objectFit = "contain"; // Preserve aspect ratio
|
|
2414
2460
|
imgElement.style.display = "block";
|
|
2415
2461
|
imgElement.style.visibility = "visible";
|
|
@@ -2593,19 +2639,29 @@ export class CanvasRenderer {
|
|
|
2593
2639
|
const rect = canvasEl?.getBoundingClientRect();
|
|
2594
2640
|
const overlayW = rect?.width || displayWidth;
|
|
2595
2641
|
const overlayH = rect?.height || displayHeight;
|
|
2596
|
-
|
|
2642
|
+
// Rotate the caption overlay to ride the video: swap to the video's own
|
|
2643
|
+
// frame box for 90°/270° and centre it so, once rotated around its centre,
|
|
2644
|
+
// it lands back over the video (see resize() for the same approach). This
|
|
2645
|
+
// render path runs ~60×/s and previously forced transform:none, undoing
|
|
2646
|
+
// the rotation set on rotate — so the rotation has to be re-applied here.
|
|
2647
|
+
const rotTxt = (((this.rotation ?? 0) % 360) + 360) % 360;
|
|
2648
|
+
const swappedTxt = rotTxt === 90 || rotTxt === 270;
|
|
2649
|
+
const ovTxtW = swappedTxt ? overlayH : overlayW;
|
|
2650
|
+
const ovTxtH = swappedTxt ? overlayW : overlayH;
|
|
2651
|
+
const bottomPadding = CanvasRenderer.computeSubtitleBottomPadding(ovTxtH);
|
|
2597
2652
|
this.subtitleOverlay.style.position = "absolute";
|
|
2598
|
-
this.subtitleOverlay.style.top = "0";
|
|
2599
|
-
this.subtitleOverlay.style.left = "0";
|
|
2600
2653
|
this.subtitleOverlay.style.right = "auto";
|
|
2601
2654
|
this.subtitleOverlay.style.bottom = "auto";
|
|
2602
|
-
this.subtitleOverlay.style.width = `${
|
|
2603
|
-
this.subtitleOverlay.style.height = `${
|
|
2655
|
+
this.subtitleOverlay.style.width = `${ovTxtW}px`;
|
|
2656
|
+
this.subtitleOverlay.style.height = `${ovTxtH}px`;
|
|
2657
|
+
this.subtitleOverlay.style.left = `${(overlayW - ovTxtW) / 2}px`;
|
|
2658
|
+
this.subtitleOverlay.style.top = `${(overlayH - ovTxtH) / 2}px`;
|
|
2604
2659
|
this.subtitleOverlay.style.margin = "0";
|
|
2605
2660
|
this.subtitleOverlay.style.padding = "0";
|
|
2606
2661
|
const effectivePad = this.subtitleControlsPadding > 0 ? this.subtitleControlsPadding : bottomPadding;
|
|
2607
2662
|
this.subtitleOverlay.style.paddingBottom = `${effectivePad}px`;
|
|
2608
|
-
this.subtitleOverlay.style.
|
|
2663
|
+
this.subtitleOverlay.style.transformOrigin = "center center";
|
|
2664
|
+
this.subtitleOverlay.style.transform = rotTxt ? `rotate(${rotTxt}deg)` : "none";
|
|
2609
2665
|
this.subtitleOverlay.style.boxSizing = "border-box";
|
|
2610
2666
|
this.subtitleOverlay.style.display = "flex";
|
|
2611
2667
|
this.subtitleOverlay.style.flexDirection = "column";
|