-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
34af4f4
commit 20d1541
Showing
8 changed files
with
221 additions
and
179 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,176 +1,214 @@ | ||
import React, { useRef } from 'react'; | ||
import { Dropdown, Button, ButtonGroup } from 'react-bootstrap'; | ||
import ReactPlayer from 'react-player'; | ||
import SceneContainer from './SceneContainer'; | ||
import { getFixedNumber } from '../utils/MathUtils'; | ||
import FormattedTime from '../components/videoPlayer/FormattedTime'; | ||
import { useVideoStore } from '../stores/VideoStore'; | ||
import { useAnnotationStore } from '../stores/AnnotationStore'; | ||
import { useObjectStore } from '../stores/ObjectStore' | ||
import React, { useRef } from "react"; | ||
import { Dropdown, Button, ButtonGroup } from "react-bootstrap"; | ||
import ReactPlayer from "react-player"; | ||
import SceneContainer from "./SceneContainer"; | ||
import { getFixedNumber } from "../utils/MathUtils"; | ||
import FormattedTime from "../components/videoPlayer/FormattedTime"; | ||
import { useObjectStore, useAnnotationStore, useVideoStore } from '../stores'; | ||
|
||
/** | ||
* Video player slide component. | ||
* | ||
* @param {void} onMouseUp Mouse up listener | ||
* @param {void} onMouseDown Mouse down listener | ||
* @param {VoidFunction} onChange Update video time | ||
* @param {Number} played Seconds played | ||
* @returns | ||
*/ | ||
const Slider = ({ onMouseUp, onMouseDown, onChange, played }) => ( | ||
<div> | ||
<input | ||
className="tactile-slider" | ||
type='range' | ||
min={ 0 } | ||
max={ 1 } | ||
step='any' | ||
value={ played } | ||
onMouseUp={ onMouseUp } | ||
onMouseDown={ onMouseDown } | ||
onChange={ onChange } | ||
onInput={ onChange } | ||
/> | ||
</div> | ||
<div> | ||
<input | ||
className="tactile-slider" | ||
type="range" | ||
min={0} | ||
max={1} | ||
step="any" | ||
value={played} | ||
onMouseUp={onMouseUp} | ||
onMouseDown={onMouseDown} | ||
onChange={onChange} | ||
onInput={onChange} | ||
/> | ||
</div> | ||
); | ||
|
||
const AnnotationView = ({camPosition, objScale}) => { | ||
/** | ||
* Annotation component view, it puts video player and 3D scene together. | ||
* | ||
* @param {Object} props.camPosition object containing position and field of view of camera properties | ||
* @returns | ||
*/ | ||
|
||
const player = useRef() | ||
const { | ||
url, | ||
playing, | ||
played, | ||
duration, | ||
playbackRate, | ||
loop, | ||
seeking, | ||
setVideoDimensions, | ||
onSeekTime, | ||
handleProgress, | ||
handleVideoPlayPause, | ||
handleVideoRewind, | ||
handleSeekingtoFalse, | ||
handleVideoDuration, | ||
handleEnded, | ||
handleSeekMouseDown, | ||
handleSeekChange, | ||
handleVideoSpeedChange } = useVideoStore(); | ||
|
||
const annotationStore = useAnnotationStore(); | ||
const objectStore = useObjectStore(); | ||
const AnnotationView = ({ camPosition }) => { | ||
const player = useRef(); | ||
const { | ||
url, | ||
playing, | ||
played, | ||
duration, | ||
playbackRate, | ||
loop, | ||
seeking, | ||
setVideoDimensions, | ||
onSeekTime, | ||
handleProgress, | ||
handleVideoPlayPause, | ||
handleVideoRewind, | ||
handleSeekingtoFalse, | ||
handleVideoDuration, | ||
handleEnded, | ||
handleSeekMouseDown, | ||
handleSeekChange, | ||
handleVideoSpeedChange, | ||
} = useVideoStore(); | ||
|
||
const findAnnotation = (t) => { | ||
//if (!editMode) return | ||
const secondsLapsed = t * duration; | ||
let currentAnnotations = annotationStore.outputAnnotation.annotations | ||
if (currentAnnotations.length <= 0) return | ||
const annotation = currentAnnotations.reduce((prev, curr) => { | ||
let closest = (Math.abs(curr.time - secondsLapsed) < Math.abs(prev.time - secondsLapsed) ? curr : prev) | ||
return closest | ||
}); | ||
const annotationStore = useAnnotationStore(); | ||
const objectStore = useObjectStore(); | ||
|
||
if (annotation !== undefined) { | ||
objectStore.handleRotation(annotation.rotation) | ||
objectStore.handleTranslation(annotation.position) | ||
objectStore.setObjScale(annotation.scale) | ||
} | ||
return | ||
} | ||
|
||
const handleSeekMouseUp = e => { | ||
handleSeekingtoFalse() | ||
player.current.seekTo(getFixedNumber(e.target.value, 5)) | ||
} | ||
const findAnnotation = (t) => { | ||
if (!annotationStore.reviewMode) return | ||
const secondsLapsed = t * duration; | ||
let currentAnnotations = annotationStore.outputAnnotation.annotations; | ||
if (currentAnnotations.length <= 0) return; | ||
const annotation = currentAnnotations.reduce((prev, curr) => { | ||
let closest = | ||
Math.abs(curr.time - secondsLapsed) < | ||
Math.abs(prev.time - secondsLapsed) | ||
? curr | ||
: prev; | ||
return closest; | ||
}); | ||
|
||
const handleRewind = () => { | ||
handleVideoRewind() | ||
player.current.seekTo(0); | ||
if (annotation !== undefined) { | ||
objectStore.handleRotation(annotation.rotation); | ||
objectStore.handleTranslation(annotation.position); | ||
objectStore.setObjScale(annotation.scale); | ||
} | ||
return; | ||
}; | ||
|
||
const onVideoReady = (e) => { | ||
const videoWidth = player.current.getInternalPlayer().videoWidth; | ||
const videoHeight = player.current.getInternalPlayer().videoHeight; | ||
setVideoDimensions(videoWidth, videoHeight) | ||
annotationStore.setVideoMetadata(e) | ||
} | ||
const handleSeekMouseUp = (e) => { | ||
handleSeekingtoFalse(); | ||
player.current.seekTo(getFixedNumber(e.target.value, 5)); | ||
}; | ||
|
||
const onProgress = state => { | ||
const { played } = state | ||
if (!seeking) handleProgress(getFixedNumber(played, 5)) | ||
findAnnotation(played) | ||
} | ||
const handleRewind = () => { | ||
handleVideoRewind(); | ||
player.current.seekTo(0); | ||
}; | ||
|
||
const onSliderChange = (e) => { | ||
let t = getFixedNumber(e.target.value, 5) | ||
handleSeekChange(t) | ||
findAnnotation(t) | ||
} | ||
const onVideoReady = (e) => { | ||
const videoWidth = player.current.getInternalPlayer().videoWidth; | ||
const videoHeight = player.current.getInternalPlayer().videoHeight; | ||
setVideoDimensions(videoWidth, videoHeight); | ||
annotationStore.setVideoMetadata(e); | ||
}; | ||
|
||
return ( | ||
<> | ||
<div className="video_box"> | ||
<div className="video_overlays"> | ||
<div className="scene-container"> | ||
<SceneContainer | ||
position={camPosition} | ||
/> | ||
</div> | ||
const onProgress = (state) => { | ||
const { played } = state; | ||
if (!seeking) handleProgress(getFixedNumber(played, 5)); | ||
findAnnotation(played); | ||
}; | ||
|
||
const onSliderChange = (e) => { | ||
let t = getFixedNumber(e.target.value, 5); | ||
handleSeekChange(t); | ||
findAnnotation(t); | ||
}; | ||
|
||
return ( | ||
<> | ||
<div className="video_box"> | ||
<div className="video_overlays"> | ||
<div className="scene-container"> | ||
<SceneContainer position={camPosition} /> | ||
</div> | ||
</div> | ||
<div className="player-wrapper"> | ||
<ReactPlayer | ||
ref={player} | ||
className="react-player" | ||
width="100%" | ||
height="100%" | ||
url={url} | ||
playing={playing} | ||
controls={false} | ||
loop={loop} | ||
playbackRate={playbackRate} | ||
progressInterval={1000 / 30} | ||
onReady={(e) => onVideoReady(e)} | ||
onStart={() => console.log("onStart")} | ||
onBuffer={() => console.log("onBuffer")} | ||
onSeek={(e) => onSeekTime(e)} | ||
onEnded={handleEnded} | ||
onError={(e) => console.log("onError", e)} | ||
onProgress={onProgress} | ||
onDuration={(e) => handleVideoDuration(e)} | ||
/> | ||
</div> | ||
</div> | ||
<div className="mt-2"> | ||
<Slider | ||
played={played} | ||
onMouseDown={handleSeekMouseDown} | ||
onChange={onSliderChange} | ||
onMouseUp={handleSeekMouseUp} | ||
/> | ||
<div className="d-flex mt-2 justify-content-between"> | ||
<div className="d-flex align-items-center"> | ||
<ButtonGroup> | ||
<Button | ||
className="d-flex align-items-center" | ||
onClick={handleRewind} | ||
> | ||
<i className="bi bi-skip-backward-circle"></i> | ||
</Button> | ||
<Button | ||
className="align-items-center" | ||
color="default" | ||
onClick={handleVideoPlayPause} | ||
> | ||
{playing ? ( | ||
<i className="bi bi-pause-circle"></i> | ||
) : ( | ||
<i className="bi bi-play-circle"></i> | ||
)} | ||
</Button> | ||
</ButtonGroup> | ||
<Dropdown className="px-2" size="sm"> | ||
<Dropdown.Toggle | ||
className="d-flex align-items-center" | ||
color="link" | ||
> | ||
{playbackRate} | ||
</Dropdown.Toggle> | ||
<Dropdown.Menu> | ||
<Dropdown.Item onClick={() => handleVideoSpeedChange(0.5)}> | ||
0.5 | ||
</Dropdown.Item> | ||
<Dropdown.Item onClick={() => handleVideoSpeedChange(1)}> | ||
1 | ||
</Dropdown.Item> | ||
<Dropdown.Item onClick={() => handleVideoSpeedChange(1.5)}> | ||
1.5 | ||
</Dropdown.Item> | ||
<Dropdown.Item onClick={() => handleVideoSpeedChange(2)}> | ||
2 | ||
</Dropdown.Item> | ||
</Dropdown.Menu> | ||
</Dropdown> | ||
</div> | ||
<div className="d-flex align-items-center"> | ||
<div className="player-control__time"> | ||
<FormattedTime seconds={played * duration} /> | ||
{" / "} | ||
<FormattedTime seconds={duration} /> | ||
</div> | ||
<div className="player-wrapper"> | ||
<ReactPlayer | ||
ref={player} | ||
className='react-player' | ||
width='100%' | ||
height='100%' | ||
url={url} | ||
playing={playing} | ||
controls={false} | ||
loop={loop} | ||
playbackRate={playbackRate} | ||
progressInterval={1000 / 30} | ||
onReady={(e) => onVideoReady(e)} | ||
onStart={() => console.log('onStart')} | ||
onBuffer={() => console.log('onBuffer')} | ||
onSeek={e => onSeekTime(e)} | ||
onEnded={handleEnded} | ||
onError={e => console.log('onError', e)} | ||
onProgress={onProgress} | ||
onDuration={e => handleVideoDuration(e)} | ||
/> | ||
</div> | ||
</div> | ||
<div className="mt-2"> | ||
<Slider | ||
played={ played } | ||
onMouseDown={handleSeekMouseDown} | ||
onChange={onSliderChange} | ||
onMouseUp={handleSeekMouseUp} | ||
/> | ||
<div className='d-flex mt-2 justify-content-between'> | ||
<div className='d-flex align-items-center'> | ||
<ButtonGroup> | ||
<Button className='d-flex align-items-center' onClick={handleRewind}> | ||
<i className="bi bi-skip-backward-circle"></i> | ||
</Button> | ||
<Button className='align-items-center' color='default' onClick={ handleVideoPlayPause }> | ||
{playing ? <i className="bi bi-pause-circle"></i> : <i className="bi bi-play-circle"></i>} | ||
</Button> | ||
</ButtonGroup> | ||
<Dropdown className="px-2" size='sm'> | ||
<Dropdown.Toggle className='d-flex align-items-center' color='link'> | ||
{ playbackRate } | ||
</Dropdown.Toggle> | ||
<Dropdown.Menu> | ||
<Dropdown.Item onClick={ () => handleVideoSpeedChange(0.5) }>0.5</Dropdown.Item> | ||
<Dropdown.Item onClick={ () => handleVideoSpeedChange(1) }>1</Dropdown.Item> | ||
<Dropdown.Item onClick={ () => handleVideoSpeedChange(1.5) }>1.5</Dropdown.Item> | ||
<Dropdown.Item onClick={ () => handleVideoSpeedChange(2) }>2</Dropdown.Item> | ||
</Dropdown.Menu> | ||
</Dropdown> | ||
</div> | ||
<div className='d-flex align-items-center'> | ||
<div className='player-control__time'> | ||
<FormattedTime seconds={ played * duration} /> | ||
{' / ' } | ||
<FormattedTime seconds={ duration } /> | ||
</div> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
) | ||
} | ||
</div> | ||
</div> | ||
</> | ||
); | ||
}; | ||
|
||
export default AnnotationView; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.