@eluvio/elv-player-js 2.1.32 → 2.1.34

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.
@@ -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;
@@ -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
@@ -198,7 +198,14 @@ const ContentVerificationControls = ({player}) => {
198
198
  );
199
199
  };
200
200
 
201
- const WebControls = ({player, playbackStarted, canPlay, recentlyInteracted, setRecentUserAction, className=""}) => {
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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eluvio/elv-player-js",
3
- "version": "2.1.32",
3
+ "version": "2.1.34",
4
4
  "description": "![Eluvio Logo](lib/static/images/Logo.png \"Eluvio Logo\")",
5
5
  "main": "dist/elv-player-js.es.js",
6
6
  "license": "MIT",