@eluvio/elv-player-js 2.1.33 → 2.1.35
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/dist/.vite/manifest.json +7 -7
- package/dist/elv-player-js.cjs.js +1 -1
- package/dist/elv-player-js.css +1 -1
- package/dist/elv-player-js.es.js +1 -1
- package/dist/{index-DjFcABDu.mjs → index-2H2xCtem.mjs} +14110 -13956
- package/dist/{index-BQZtvvaT.js → index-BE8WVWvI.js} +1 -1
- package/dist/{index-D18XCfzI.js → index-C0oUvvox.js} +90 -90
- package/dist/{index-BAMTZqd_.mjs → index-Do5hokOx.mjs} +1 -1
- package/lib/player/Controls.js +13 -0
- package/lib/player/Player.js +70 -2
- package/lib/player/PlayerParameters.js +5 -0
- package/lib/player/ThumbnailHandler.js +1 -1
- package/lib/static/icons/Icons.js +1 -0
- package/lib/static/icons/svgs/overlay.svg +7 -0
- package/lib/static/stylesheets/controls-web.module.scss +4 -0
- package/lib/static/stylesheets/player.module.scss +7 -0
- package/lib/ui/BuildIcons.cjs +2 -1
- package/lib/ui/Overlay.jsx +159 -0
- package/lib/ui/PlayerUI.jsx +9 -0
- package/lib/ui/WebControls.jsx +21 -1
- package/package.json +1 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { c as DI, r as tI, a as TA, b as rI, d as oA, e as uA, f as PA, g as cI } from "./index-
|
|
1
|
+
import { c as DI, r as tI, a as TA, b as rI, d as oA, e as uA, f as PA, g as cI } from "./index-2H2xCtem.mjs";
|
|
2
2
|
class BA {
|
|
3
3
|
constructor(B) {
|
|
4
4
|
this.wasm = B;
|
package/lib/player/Controls.js
CHANGED
|
@@ -1095,6 +1095,19 @@ class PlayerControls {
|
|
|
1095
1095
|
this.player.Destroy();
|
|
1096
1096
|
}
|
|
1097
1097
|
|
|
1098
|
+
OverlayAvailable() {
|
|
1099
|
+
return !!this.player.__poseOverlayTags;
|
|
1100
|
+
}
|
|
1101
|
+
|
|
1102
|
+
OverlayVisible() {
|
|
1103
|
+
return this.player.__showOverlay;
|
|
1104
|
+
}
|
|
1105
|
+
|
|
1106
|
+
ToggleOverlayVisibility() {
|
|
1107
|
+
this.player.__showOverlay = !this.player.__showOverlay;
|
|
1108
|
+
this.player.__SettingsUpdate();
|
|
1109
|
+
}
|
|
1110
|
+
|
|
1098
1111
|
GetDebugInfo() {
|
|
1099
1112
|
const sourceOptions = JSON.parse(JSON.stringify(this.player.sourceOptions));
|
|
1100
1113
|
delete sourceOptions.playoutOptions;
|
package/lib/player/Player.js
CHANGED
|
@@ -330,6 +330,16 @@ export class EluvioPlayer {
|
|
|
330
330
|
|
|
331
331
|
const offset = (properties || {}).start_offset_float || 0;
|
|
332
332
|
const thumbnailOffset = (clipStart || 0) + (offset || 0);
|
|
333
|
+
let frameRate = (properties || {}).rate;
|
|
334
|
+
if(frameRate && typeof frameRate === "string") {
|
|
335
|
+
const [num, denom] = frameRate.split("/");
|
|
336
|
+
|
|
337
|
+
if(!denom) {
|
|
338
|
+
frameRate = parseInt(num);
|
|
339
|
+
} else {
|
|
340
|
+
frameRate = parseInt(num) / parseInt(denom);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
333
343
|
|
|
334
344
|
return {
|
|
335
345
|
playoutParameters: {
|
|
@@ -351,6 +361,8 @@ export class EluvioPlayer {
|
|
|
351
361
|
clipEnd: options.clip_end,
|
|
352
362
|
trimOffset: offset,
|
|
353
363
|
thumbnailOffset,
|
|
364
|
+
frameRateRat: properties.rate,
|
|
365
|
+
frameRate,
|
|
354
366
|
sessionId: this.sourceOptions.playoutOptions.sessionId,
|
|
355
367
|
multiviewOptions: {
|
|
356
368
|
enabled: this.sourceOptions.playoutOptions.multiview,
|
|
@@ -552,7 +564,9 @@ export class EluvioPlayer {
|
|
|
552
564
|
offering,
|
|
553
565
|
compositionKey,
|
|
554
566
|
clipStart,
|
|
555
|
-
clipEnd
|
|
567
|
+
clipEnd,
|
|
568
|
+
frameRate,
|
|
569
|
+
frameRateRat
|
|
556
570
|
} = await this.__PlayoutOptions();
|
|
557
571
|
|
|
558
572
|
this.playoutInfo = {
|
|
@@ -563,7 +577,9 @@ export class EluvioPlayer {
|
|
|
563
577
|
trimOffset,
|
|
564
578
|
thumbnailOffset,
|
|
565
579
|
clipStart,
|
|
566
|
-
clipEnd
|
|
580
|
+
clipEnd,
|
|
581
|
+
frameRate,
|
|
582
|
+
frameRateRat
|
|
567
583
|
};
|
|
568
584
|
|
|
569
585
|
this.contentHash = versionHash;
|
|
@@ -618,6 +634,15 @@ export class EluvioPlayer {
|
|
|
618
634
|
.catch(error => this.Log(error, true));
|
|
619
635
|
}
|
|
620
636
|
|
|
637
|
+
if(this.playerOptions.loadPoseOverlay) {
|
|
638
|
+
this.__LoadPoseOverlayTags({...(this.playoutInfo || {})})
|
|
639
|
+
.then(poseOverlayTags => {
|
|
640
|
+
this.__poseOverlayTags = poseOverlayTags;
|
|
641
|
+
this.__showOverlay = true;
|
|
642
|
+
})
|
|
643
|
+
.catch(error => this.Log(error, true));
|
|
644
|
+
}
|
|
645
|
+
|
|
621
646
|
if(this.playerOptions.playerCallback) {
|
|
622
647
|
this.playerOptions.playerCallback({
|
|
623
648
|
player: this,
|
|
@@ -1534,6 +1559,49 @@ export class EluvioPlayer {
|
|
|
1534
1559
|
}));
|
|
1535
1560
|
}
|
|
1536
1561
|
|
|
1562
|
+
async __LoadPoseOverlayTags({objectId, offering, compositionKey, clipStart, clipEnd}) {
|
|
1563
|
+
const {tracks} = await this.__QueryAIAPI({
|
|
1564
|
+
objectId,
|
|
1565
|
+
path: UrlJoin("/tagstore", objectId, "tracks"),
|
|
1566
|
+
queryParams: {
|
|
1567
|
+
has_frame_info: true
|
|
1568
|
+
},
|
|
1569
|
+
format: "JSON"
|
|
1570
|
+
});
|
|
1571
|
+
|
|
1572
|
+
if(!tracks.find(track => track.name === "pose")) {
|
|
1573
|
+
return;
|
|
1574
|
+
}
|
|
1575
|
+
|
|
1576
|
+
let frameTags = {};
|
|
1577
|
+
((await this.__QueryAIAPI({
|
|
1578
|
+
objectId,
|
|
1579
|
+
path: offering || compositionKey ?
|
|
1580
|
+
UrlJoin("/tagstore", objectId, "compositions", "tags") :
|
|
1581
|
+
UrlJoin("/tagstore", objectId, "tags"),
|
|
1582
|
+
queryParams: {
|
|
1583
|
+
has_frame_info: true,
|
|
1584
|
+
channel_key: compositionKey,
|
|
1585
|
+
offering_key: offering,
|
|
1586
|
+
limit: 1000000,
|
|
1587
|
+
track: "pose",
|
|
1588
|
+
clip_start: clipStart,
|
|
1589
|
+
clip_end: clipEnd
|
|
1590
|
+
},
|
|
1591
|
+
format: "JSON"
|
|
1592
|
+
})).tags || [])
|
|
1593
|
+
.forEach(tag => {
|
|
1594
|
+
const frame = parseInt(tag.frame_info.frame_idx);
|
|
1595
|
+
if(!frameTags[frame]) {
|
|
1596
|
+
frameTags[frame] = [];
|
|
1597
|
+
}
|
|
1598
|
+
|
|
1599
|
+
frameTags[frame].push(tag);
|
|
1600
|
+
});
|
|
1601
|
+
|
|
1602
|
+
return frameTags;
|
|
1603
|
+
}
|
|
1604
|
+
|
|
1537
1605
|
async __QueryAIAPI({
|
|
1538
1606
|
server="ai",
|
|
1539
1607
|
method="GET",
|
|
@@ -108,6 +108,10 @@ export const PlayerParameters = {
|
|
|
108
108
|
loadChapters: {
|
|
109
109
|
OFF: false,
|
|
110
110
|
ON: true
|
|
111
|
+
},
|
|
112
|
+
loadPoseOverlay: {
|
|
113
|
+
OFF: false,
|
|
114
|
+
ON: true
|
|
111
115
|
}
|
|
112
116
|
};
|
|
113
117
|
|
|
@@ -190,6 +194,7 @@ export const DefaultParameters = {
|
|
|
190
194
|
allowCasting: PlayerParameters.allowCasting.ON,
|
|
191
195
|
preferNativeHLS: PlayerParameters.preferNativeHLS.OFF,
|
|
192
196
|
loadChapters: PlayerParameters.loadChapters.OFF,
|
|
197
|
+
loadPoseOverlay: PlayerParameters.loadPoseOverlay.OFF,
|
|
193
198
|
startTime: undefined,
|
|
194
199
|
startProgress: undefined,
|
|
195
200
|
hlsjsOptions: undefined,
|
|
@@ -188,7 +188,7 @@ class ThumbnailHandler {
|
|
|
188
188
|
|
|
189
189
|
if(!thumbnailIndex) { return; }
|
|
190
190
|
|
|
191
|
-
const tag = this.thumbnails && this.thumbnails[thumbnailIndex
|
|
191
|
+
const tag = this.thumbnails && this.thumbnails[thumbnailIndex.toString()];
|
|
192
192
|
|
|
193
193
|
if(!tag) {
|
|
194
194
|
return;
|
|
@@ -35,3 +35,4 @@ export const CopyIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\"
|
|
|
35
35
|
export const AirplayIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-airplay\"><path d=\"M5 17H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2h-1\"></path><polygon points=\"12 15 17 21 7 21 12 15\"></polygon></svg>";
|
|
36
36
|
export const ChromecastIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-cast\"><path d=\"M2 16.1A5 5 0 0 1 5.9 20M2 12.05A9 9 0 0 1 9.95 20M2 8V6a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2h-6\"></path><line x1=\"2\" y1=\"20\" x2=\"2.01\" y2=\"20\"></line></svg>";
|
|
37
37
|
export const InfoIcon = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" class=\"feather feather-info\"><circle cx=\"12\" cy=\"12\" r=\"10\"></circle><line x1=\"12\" y1=\"16\" x2=\"12\" y2=\"12\"></line><line x1=\"12\" y1=\"8\" x2=\"12.01\" y2=\"8\"></line></svg>";
|
|
38
|
+
export const OverlayIcon = "<svg width=\"20\" height=\"20\" viewBox=\"0 0 20 20\" fill=\"none\" xmlns=\"http://www.w3.org/2000/svg\"><path d=\"M5.16602 7.29169H6.45768C6.91792 7.29169 7.29102 6.91859 7.29102 6.45835V5.16669H12.9576V6.45835C12.9576 6.91859 13.3307 7.29169 13.7909 7.29169H15.0826V12.9584H13.7909C13.3307 12.9584 12.9576 13.3314 12.9576 13.7917V15.0834H7.29102V13.7917C7.29102 13.3314 6.91792 12.9584 6.45768 12.9584H5.16602V7.29169Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.75 4.14352C3.75 4.03915 3.79146 3.93906 3.86526 3.86526C3.93906 3.79146 4.03915 3.75 4.14352 3.75H6.89815C7.00252 3.75 7.10261 3.79146 7.17641 3.86526C7.25021 3.93906 7.29167 4.03915 7.29167 4.14352V6.89815C7.29167 7.00252 7.25021 7.10261 7.17641 7.17641C7.10261 7.25021 7.00252 7.29167 6.89815 7.29167H4.14352C4.03915 7.29167 3.93906 7.25021 3.86526 7.17641C3.79146 7.10261 3.75 7.00252 3.75 6.89815V4.14352Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M3.75 13.3518C3.75 13.2475 3.79146 13.1474 3.86526 13.0736C3.93906 12.9998 4.03915 12.9583 4.14352 12.9583H6.89815C7.00252 12.9583 7.10261 12.9998 7.17641 13.0736C7.25021 13.1474 7.29167 13.2475 7.29167 13.3518V16.1065C7.29167 16.2108 7.25021 16.3109 7.17641 16.3847C7.10261 16.4585 7.00252 16.5 6.89815 16.5H4.14352C4.03915 16.5 3.93906 16.4585 3.86526 16.3847C3.79146 16.3109 3.75 16.2108 3.75 16.1065V13.3518Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12.959 13.3518C12.959 13.2475 13.0004 13.1474 13.0742 13.0736C13.148 12.9998 13.2481 12.9583 13.3525 12.9583H16.1071C16.2115 12.9583 16.3116 12.9998 16.3854 13.0736C16.4592 13.1474 16.5007 13.2475 16.5007 13.3518V16.1065C16.5007 16.2108 16.4592 16.3109 16.3854 16.3847C16.3116 16.4585 16.2115 16.5 16.1071 16.5H13.3525C13.2481 16.5 13.148 16.4585 13.0742 16.3847C13.0004 16.3109 12.959 16.2108 12.959 16.1065V13.3518Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/><path d=\"M12.959 4.14352C12.959 4.03915 13.0004 3.93906 13.0742 3.86526C13.148 3.79146 13.2481 3.75 13.3525 3.75H16.1071C16.2115 3.75 16.3116 3.79146 16.3854 3.86526C16.4592 3.93906 16.5007 4.03915 16.5007 4.14352V6.89815C16.5007 7.00252 16.4592 7.10261 16.3854 7.17641C16.3116 7.25021 16.2115 7.29167 16.1071 7.29167H13.3525C13.2481 7.29167 13.148 7.25021 13.0742 7.17641C13.0004 7.10261 12.959 7.00252 12.959 6.89815V4.14352Z\" stroke=\"currentColor\" stroke-width=\"1.5\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>";
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<path d="M5.16602 7.29169H6.45768C6.91792 7.29169 7.29102 6.91859 7.29102 6.45835V5.16669H12.9576V6.45835C12.9576 6.91859 13.3307 7.29169 13.7909 7.29169H15.0826V12.9584H13.7909C13.3307 12.9584 12.9576 13.3314 12.9576 13.7917V15.0834H7.29102V13.7917C7.29102 13.3314 6.91792 12.9584 6.45768 12.9584H5.16602V7.29169Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
3
|
+
<path d="M3.75 4.14352C3.75 4.03915 3.79146 3.93906 3.86526 3.86526C3.93906 3.79146 4.03915 3.75 4.14352 3.75H6.89815C7.00252 3.75 7.10261 3.79146 7.17641 3.86526C7.25021 3.93906 7.29167 4.03915 7.29167 4.14352V6.89815C7.29167 7.00252 7.25021 7.10261 7.17641 7.17641C7.10261 7.25021 7.00252 7.29167 6.89815 7.29167H4.14352C4.03915 7.29167 3.93906 7.25021 3.86526 7.17641C3.79146 7.10261 3.75 7.00252 3.75 6.89815V4.14352Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
4
|
+
<path d="M3.75 13.3518C3.75 13.2475 3.79146 13.1474 3.86526 13.0736C3.93906 12.9998 4.03915 12.9583 4.14352 12.9583H6.89815C7.00252 12.9583 7.10261 12.9998 7.17641 13.0736C7.25021 13.1474 7.29167 13.2475 7.29167 13.3518V16.1065C7.29167 16.2108 7.25021 16.3109 7.17641 16.3847C7.10261 16.4585 7.00252 16.5 6.89815 16.5H4.14352C4.03915 16.5 3.93906 16.4585 3.86526 16.3847C3.79146 16.3109 3.75 16.2108 3.75 16.1065V13.3518Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
5
|
+
<path d="M12.959 13.3518C12.959 13.2475 13.0004 13.1474 13.0742 13.0736C13.148 12.9998 13.2481 12.9583 13.3525 12.9583H16.1071C16.2115 12.9583 16.3116 12.9998 16.3854 13.0736C16.4592 13.1474 16.5007 13.2475 16.5007 13.3518V16.1065C16.5007 16.2108 16.4592 16.3109 16.3854 16.3847C16.3116 16.4585 16.2115 16.5 16.1071 16.5H13.3525C13.2481 16.5 13.148 16.4585 13.0742 16.3847C13.0004 16.3109 12.959 16.2108 12.959 16.1065V13.3518Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
6
|
+
<path d="M12.959 4.14352C12.959 4.03915 13.0004 3.93906 13.0742 3.86526C13.148 3.79146 13.2481 3.75 13.3525 3.75H16.1071C16.2115 3.75 16.3116 3.79146 16.3854 3.86526C16.4592 3.93906 16.5007 4.03915 16.5007 4.14352V6.89815C16.5007 7.00252 16.4592 7.10261 16.3854 7.17641C16.3116 7.25021 16.2115 7.29167 16.1071 7.29167H13.3525C13.2481 7.29167 13.148 7.25021 13.0742 7.17641C13.0004 7.10261 12.959 7.00252 12.959 6.89815V4.14352Z" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
|
7
|
+
</svg>
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
font-family: system-ui, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
|
13
13
|
height: 100%;
|
|
14
14
|
inset: 0;
|
|
15
|
+
overflow: hidden;
|
|
15
16
|
position: absolute;
|
|
16
17
|
width: 100%;
|
|
17
18
|
|
|
@@ -130,6 +131,12 @@
|
|
|
130
131
|
}
|
|
131
132
|
}
|
|
132
133
|
|
|
134
|
+
.overlay {
|
|
135
|
+
pointer-events: none;
|
|
136
|
+
position: absolute;
|
|
137
|
+
z-index: 1000;
|
|
138
|
+
}
|
|
139
|
+
|
|
133
140
|
:global(.__eluvio-player--size-md),
|
|
134
141
|
:global(.__eluvio-player--size-sm) {
|
|
135
142
|
.error-message {
|
package/lib/ui/BuildIcons.cjs
CHANGED
|
@@ -37,7 +37,8 @@ const iconSource = {
|
|
|
37
37
|
CopyIcon: Path.resolve(__dirname, "../static/icons/svgs/copy.svg"),
|
|
38
38
|
AirplayIcon: Path.resolve(__dirname, "../static/icons/svgs/airplay.svg"),
|
|
39
39
|
ChromecastIcon: Path.resolve(__dirname, "../static/icons/svgs/cast.svg"),
|
|
40
|
-
InfoIcon: Path.resolve(__dirname, "../static/icons/svgs/info.svg")
|
|
40
|
+
InfoIcon: Path.resolve(__dirname, "../static/icons/svgs/info.svg"),
|
|
41
|
+
OverlayIcon: Path.resolve(__dirname, "../static/icons/svgs/overlay.svg")
|
|
41
42
|
};
|
|
42
43
|
|
|
43
44
|
let iconFile = "// WARNING: Do not edit this file manually\n";
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import PlayerStyles from "../static/stylesheets/player.module.scss";
|
|
2
|
+
import {useEffect, useState} from "react";
|
|
3
|
+
|
|
4
|
+
const POINT_CONNECTIONS = [["Nose","LEyeIn"],["LEyeIn","LEye"],["LEye","REyeOut"],["REyeOut","LEar"],["Nose","REyeIn"],["REyeIn","REye"],["REye","REyeOut"],["REyeOut","REar"],["MouthL","MouthR"],["LShoulder","RShoulder"],["LShoulder","LElbow"],["LElbow","LWrist"],["LWrist","LPinky"],["LWrist","LIndex"],["LWrist","LThumb"],["LPinky","LIndex"],["RShoulder","RElbow"],["RElbow","RWrist"],["RWrist","RPinky"],["RWrist","RIndex"],["RWrist","RThumb"],["RPinky","RIndex"],["LShoulder","LHip"],["RShoulder","RHip"],["LHip","RHip"],["LHip","LKnee"],["RHip","RKnee"],["LKnee","LAnkle"],["RKnee","RAnkle"],["LAnkle","LHeel"],["RAnkle","RHeel"],["LHeel","LFootIdx"],["RHeel","RFootIdx"],["LAnkle","LFootIdx"],["RAnkle","RFootIdx"]];
|
|
5
|
+
|
|
6
|
+
let frameSpread = 5;
|
|
7
|
+
const Canvas = ({tags, portalDimensions, videoDimensions}) => {
|
|
8
|
+
const [canvas, setCanvas] = useState(null);
|
|
9
|
+
|
|
10
|
+
useEffect(() => {
|
|
11
|
+
if(!canvas || !portalDimensions || videoDimensions.videoWidth === 0) { return; }
|
|
12
|
+
|
|
13
|
+
canvas.width = canvas.getBoundingClientRect().width;
|
|
14
|
+
canvas.height = canvas.getBoundingClientRect().height;
|
|
15
|
+
|
|
16
|
+
const color = {
|
|
17
|
+
r: 255,
|
|
18
|
+
g: 255,
|
|
19
|
+
b: 255
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
// Draw
|
|
23
|
+
const context = canvas.getContext("2d");
|
|
24
|
+
const width = context.canvas.width;
|
|
25
|
+
const height = context.canvas.height;
|
|
26
|
+
const toHex = n => n.toString(16).padStart(2, "0");
|
|
27
|
+
|
|
28
|
+
context.clearRect(0, 0, context.canvas.width, context.canvas.height);
|
|
29
|
+
context.lineWidth = 3;
|
|
30
|
+
|
|
31
|
+
if(!tags || tags.length === 0) { return; }
|
|
32
|
+
|
|
33
|
+
tags.forEach(tag => {
|
|
34
|
+
if(!tag || !tag.additional_info || !tag.additional_info.pose) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
context.lineWidth = 3;
|
|
39
|
+
context.strokeStyle = `#${toHex(color.r)}${toHex(color.g)}${toHex(color.b)}`;
|
|
40
|
+
context.fillStyle = `#${toHex(color.r)}${toHex(color.g)}${toHex(color.b)}`;
|
|
41
|
+
|
|
42
|
+
context.globalAlpha = 0.7;
|
|
43
|
+
|
|
44
|
+
Object.values(tag.additional_info.pose).forEach(([x, y]) => {
|
|
45
|
+
context.beginPath();
|
|
46
|
+
context.arc(x * width, y * height, 1.5, 0, 2 * Math.PI);
|
|
47
|
+
context.fill();
|
|
48
|
+
context.stroke();
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
POINT_CONNECTIONS
|
|
52
|
+
.forEach(([start, end]) => {
|
|
53
|
+
if(!tag.additional_info.pose[start] || !tag.additional_info.pose[end]) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const [startX, startY] = tag.additional_info.pose[start];
|
|
57
|
+
const [endX, endY] = tag.additional_info.pose[end];
|
|
58
|
+
|
|
59
|
+
context.beginPath();
|
|
60
|
+
context.moveTo(startX * width, startY * height);
|
|
61
|
+
context.lineTo(endX * width, endY * height);
|
|
62
|
+
context.stroke();
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
}, [tags]);
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
if(!portalDimensions || videoDimensions.videoWidth === 0) { return null; }
|
|
69
|
+
|
|
70
|
+
const portalAspectRatio = portalDimensions.width / portalDimensions.height;
|
|
71
|
+
const videoAspectRatio = videoDimensions.videoWidth / videoDimensions.videoHeight;
|
|
72
|
+
|
|
73
|
+
let params = {};
|
|
74
|
+
if(portalAspectRatio < videoAspectRatio) {
|
|
75
|
+
// Vertical padding
|
|
76
|
+
params.width = portalDimensions.width;
|
|
77
|
+
params.height = portalDimensions.width / videoAspectRatio;
|
|
78
|
+
params.left = 0;
|
|
79
|
+
params.top = (portalDimensions.height - (portalDimensions.width / videoAspectRatio)) / 2;
|
|
80
|
+
} else {
|
|
81
|
+
// Horizontal padding
|
|
82
|
+
params.height = portalDimensions.height;
|
|
83
|
+
params.width = portalDimensions.height * videoAspectRatio;
|
|
84
|
+
params.top = 0;
|
|
85
|
+
params.left = (portalDimensions.width - (portalDimensions.height * videoAspectRatio)) / 2;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
return (
|
|
89
|
+
<canvas
|
|
90
|
+
ref={setCanvas}
|
|
91
|
+
style={params}
|
|
92
|
+
className={PlayerStyles["overlay"]}
|
|
93
|
+
/>
|
|
94
|
+
);
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
const Overlay = ({player}) => {
|
|
98
|
+
const [portalDimensions, setPortalDimensions] = useState(null);
|
|
99
|
+
const [frame, setFrame] = useState(null);
|
|
100
|
+
|
|
101
|
+
useEffect(() => {
|
|
102
|
+
const resizeObserver = new ResizeObserver(() =>
|
|
103
|
+
setPortalDimensions(player.video.getBoundingClientRect())
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
resizeObserver.observe(player.video);
|
|
107
|
+
|
|
108
|
+
return () => {
|
|
109
|
+
resizeObserver.disconnect();
|
|
110
|
+
};
|
|
111
|
+
}, [player.video]);
|
|
112
|
+
|
|
113
|
+
useEffect(() => {
|
|
114
|
+
const frameRate = (player.playoutInfo || {}).frameRate;
|
|
115
|
+
|
|
116
|
+
if(!frameRate) { return; }
|
|
117
|
+
|
|
118
|
+
const StartInterval = () => {
|
|
119
|
+
clearInterval(player.__frameInterval);
|
|
120
|
+
|
|
121
|
+
player.__frameInterval = setInterval(
|
|
122
|
+
() => setFrame(Math.floor(player.video.currentTime * frameRate)),
|
|
123
|
+
1000 / player.playoutInfo.frameRate
|
|
124
|
+
);
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
player.controls.RegisterVideoEventListener("play", StartInterval);
|
|
128
|
+
player.controls.RegisterVideoEventListener(
|
|
129
|
+
"pause",
|
|
130
|
+
() => clearInterval(player.__frameInterval)
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
if(!player.video.paused) {
|
|
134
|
+
StartInterval();
|
|
135
|
+
}
|
|
136
|
+
}, [(player.playoutInfo || {}).frameRate]);
|
|
137
|
+
|
|
138
|
+
let tags;
|
|
139
|
+
for(let i = frame; i > frame - frameSpread; i--) {
|
|
140
|
+
tags = player.__poseOverlayTags && player.__poseOverlayTags[i];
|
|
141
|
+
|
|
142
|
+
if(tags && tags.length > 0) {
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return (
|
|
148
|
+
<Canvas
|
|
149
|
+
tags={tags}
|
|
150
|
+
portalDimensions={portalDimensions}
|
|
151
|
+
videoDimensions={{
|
|
152
|
+
videoWidth: player.video.videoWidth,
|
|
153
|
+
videoHeight: player.video.videoHeight
|
|
154
|
+
}}
|
|
155
|
+
/>
|
|
156
|
+
);
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
export default Overlay;
|
package/lib/ui/PlayerUI.jsx
CHANGED
|
@@ -20,6 +20,7 @@ import TVControls from "./TVControls.jsx";
|
|
|
20
20
|
import PlayerProfileForm from "./PlayerProfileForm.jsx";
|
|
21
21
|
import {ImageUrl, MergeDefaultParameters, MergeParameters} from "./Common.js";
|
|
22
22
|
import * as Icons from "../static/icons/Icons";
|
|
23
|
+
import Overlay from "./Overlay";
|
|
23
24
|
|
|
24
25
|
const Poster = ({player}) => {
|
|
25
26
|
const [imageUrl, setImageUrl] = useState(undefined);
|
|
@@ -75,6 +76,7 @@ const PlayerUI = ({
|
|
|
75
76
|
const [recentUserAction, setRecentUserAction] = useState(undefined);
|
|
76
77
|
const [allowRotation, setAllowRotation] = useState(undefined);
|
|
77
78
|
const [casting, setCasting] = useState(false);
|
|
79
|
+
const [showOverlay, setShowOverlay] = useState(false);
|
|
78
80
|
const videoRef = useRef();
|
|
79
81
|
|
|
80
82
|
const playerSet = !!player;
|
|
@@ -126,6 +128,7 @@ const PlayerUI = ({
|
|
|
126
128
|
setPlayerInitialized(!newPlayer.loading);
|
|
127
129
|
setShowPlayerProfileForm(newPlayer.__showPlayerProfileForm);
|
|
128
130
|
setCasting(newPlayer && newPlayer.casting);
|
|
131
|
+
setShowOverlay(newPlayer.controls.OverlayVisible());
|
|
129
132
|
}
|
|
130
133
|
);
|
|
131
134
|
|
|
@@ -254,6 +257,10 @@ const PlayerUI = ({
|
|
|
254
257
|
(playbackStarted && !parameters.playerOptions.permanentPoster) ? null :
|
|
255
258
|
<Poster player={player} />
|
|
256
259
|
}
|
|
260
|
+
{
|
|
261
|
+
!showOverlay ? null :
|
|
262
|
+
<Overlay player={player} />
|
|
263
|
+
}
|
|
257
264
|
{
|
|
258
265
|
playerInitialized || errorMessage || !parameters.playerOptions.showLoader ? null :
|
|
259
266
|
<div className={PlayerStyles["spinner-container"]}>
|
|
@@ -290,6 +297,8 @@ const PlayerUI = ({
|
|
|
290
297
|
canPlay={canPlay}
|
|
291
298
|
recentlyInteracted={recentlyInteracted}
|
|
292
299
|
setRecentUserAction={onUserAction}
|
|
300
|
+
showOverlay={showOverlay}
|
|
301
|
+
setShowOverlay={setShowOverlay}
|
|
293
302
|
className={PlayerStyles.controls}
|
|
294
303
|
/> :
|
|
295
304
|
<TVControls
|
package/lib/ui/WebControls.jsx
CHANGED
|
@@ -198,7 +198,14 @@ const ContentVerificationControls = ({player}) => {
|
|
|
198
198
|
);
|
|
199
199
|
};
|
|
200
200
|
|
|
201
|
-
const WebControls = ({
|
|
201
|
+
const WebControls = ({
|
|
202
|
+
player,
|
|
203
|
+
playbackStarted,
|
|
204
|
+
canPlay,
|
|
205
|
+
recentlyInteracted,
|
|
206
|
+
setRecentUserAction,
|
|
207
|
+
className=""
|
|
208
|
+
}) => {
|
|
202
209
|
const [videoState, setVideoState] = useState(undefined);
|
|
203
210
|
const [playerClickHandler, setPlayerClickHandler] = useState(undefined);
|
|
204
211
|
const [menuVisible, setMenuVisible] = useState(player.controls.IsMenuVisible());
|
|
@@ -292,6 +299,19 @@ const WebControls = ({player, playbackStarted, canPlay, recentlyInteracted, setR
|
|
|
292
299
|
/>
|
|
293
300
|
}
|
|
294
301
|
|
|
302
|
+
{
|
|
303
|
+
!player.controls.OverlayAvailable() ? null :
|
|
304
|
+
<IconButton
|
|
305
|
+
aria-label="Toggle Overlay"
|
|
306
|
+
onClick={() => player.controls.ToggleOverlayVisibility()}
|
|
307
|
+
icon={Icons.OverlayIcon}
|
|
308
|
+
className={[
|
|
309
|
+
ControlStyles["icon-button--no-padding"],
|
|
310
|
+
player.controls.OverlayVisible() ? ControlStyles["icon-button-active"] : ""
|
|
311
|
+
].join(" ")}
|
|
312
|
+
/>
|
|
313
|
+
}
|
|
314
|
+
|
|
295
315
|
{
|
|
296
316
|
!player.controls.IsRotatable() ? null :
|
|
297
317
|
<IconButton
|