Reputation: 17220
I have the following React component that grabs a video frame and loads the frame image into another image component upon specific events(pause, seek).
I wish to be able to set the current video frame position on rendering of the video element then add a seek event afterwards .
The problem I am experiencing is setting the frame position in componentDidMount with: video.currentTime = this.props.currentVideoFramePosition actually calls the seek event even though I added the event afterwards.
How can I modify the below code to set the current time of the video without triggering the seek event.
I am trying to avoid this on page load because the draw function is returning a value to another component which I do not want…….
import React from 'react';
export default class MyComponent extends React.Component {
constructor() {
super();
const self = this;
this.frameCaptureListener = function(e){
self.draw();
};
}
componentDidMount() {
var video = document.getElementById('video');
document.getElementById('video-canvas').style.display='none';
video.currentTime = this.props.currentVideoFramePosition;
video.addEventListener('pause', this.frameCaptureListener, false);
video.addEventListener('seeked', this.frameCaptureListener, false);
}
componentWillUnmount(){
var video = document.getElementById('video');
video.removeEventListener('pause', this.frameCaptureListener, false );
video.removeEventListener('seeked', this.frameCaptureListener, false);
}
draw(){
var video = document.getElementById('video');
var canvas = document.getElementById('video-canvas');
var context = canvas.getContext('2d');
context.clearRect(0, 0, canvas.width, canvas.height);
canvas.width = 1280;
canvas.height = 720;
context.drawImage( video, 0, 0, canvas.width, canvas.height);
var dataURL = canvas.toDataURL();
video.setAttribute('crossOrigin', 'anonymous');
var frameData = {imgSrc:dataURL, lastFramePosition:video.currentTime};
return this.props.onPause(frameData);
}
onArrowNavClick(navNum){
const self = this;
var video = document.getElementById('video');
video.currentTime = video.currentTime + navNum;
video.pause();
}
render(){
const videoUrl = this.props.videoUrl;
return(
<div>
<div className="framegrab-videocontainer">
<img src="/images/arrow_left_grab.svg" className="arrow-left" onClick={() => this.onArrowNavClick(-1)}></img>
<video id="video" src={videoUrl} className="framegrab-video" controls crossOrigin="anonymous" />
<img src="/images/arrow_right_grab.svg" className="arrow-right" onClick={() => this.onArrowNavClick(1)}></img>
</div>
<canvas id="video-canvas" ></canvas>
</div>
);
}
}
Upvotes: 0
Views: 2407
Reputation: 4945
Here is how I am doing it with audio. Your problem with triggering seeking might be fixed by using a if (video.captureTime == props.captureTime) return; in frameCaptureListener.
import React from 'react';
import kshuffle, {knuthShuffle} from 'knuth-shuffle';
import JProgressBar from '../common/jProgressBar';
import PlayerActions from './player.actions';
let PlayerCtrlSty = {
backgroundColor: '#072202',
color: '#eaab5f',
margin: 'auto',
padding: '3px',
width: '320px'
}
let timerLeftSty = {minWidth: '40px'}
let timerRightSty = {textAlign: 'right', minWidth: '40px'}
let getTime = (time) => {
var minutes = time < 60 ? 0 : Math.floor(time / 60);
var seconds = Math.floor(time - (minutes * 60)) * .01;
return (minutes + seconds).toFixed(2);
}
class PlayerCtrlRender extends React.Component {
render() {
let index = this.state.playIndex;
let currentTrack = this.state.randomOn ? this.state.shuffledQueue[index] : this.props.queue[index];
let source = 'http://192.168.0.101:3950/play/' + currentTrack.location;
let title = currentTrack.title;
let progressData = {count: this.state.progressCount * 100, index: this.state.progressIndex * 100};
return (
<div id='PlayerCtrlSty' style={PlayerCtrlSty}>
<div className='FlexBox'>
<div style={timerLeftSty}>{this.state.progressIndex}</div>
<PlayerActions playing={this.state.isPlaying} clickHandler={this.clickHandler}/>
<div style={timerRightSty}>{this.state.progressCount}</div>
</div>
<JProgressBar data={progressData} position='none' />
<div id="title" style={{textAlign: 'center'}}>{title}</div>
<audio
ref="audioDiv"
src={source}
onDurationChange={this.onDurationChange}
onTimeUpdate={this.onTimeUpdate}
onEnded={this.nextSong}
/>
</div>
);
}
}
export default class PlayerCtrl extends PlayerCtrlRender {
constructor() {
super();
this.state = {
playIndex: 0,
queueLength: 1,
isPlaying: false,
progressCount: 0,
progressIndex: 0,
shuffledQueue: [{title: '', location: ''}],
randomOn: false
};
}
componentDidMount = () => {
let queue = knuthShuffle(this.props.queue.slice(0));
this.setState({queueLength: queue.length, shuffledQueue: queue});
this.refs.audioDiv.volume = .1;
};
clickHandler = (buttonid) => {
this.refs.audioDiv.autoplay = false;
switch (buttonid) {
case 'play': this.refs.audioDiv.play(); this.setState({isPlaying: true}); break;
case 'pause': this.refs.audioDiv.pause(); this.setState({isPlaying: false}); break;
case 'back': this.refs.audioDiv.currentTime = 0; break;
case 'next': this.nextSong(); break;
case 'random': this.refs.audioDiv.autoplay = this.state.isPlaying;
this.setState({randomOn: !this.state.randomOn}); break;
}
};
nextSong = () => {
this.refs.audioDiv.autoplay = this.state.isPlaying;
this.refs.audioDiv.currentTime = 0;
let newIndex = this.state.playIndex + 1;
if (newIndex == this.state.queueLength) newIndex = 0;
this.setState({playIndex: newIndex});
};
onDurationChange = () => {
let duration = this.refs.audioDiv.duration;
duration = getTime(Math.floor(duration));
this.setState({progressCount: duration})
this.setState({progressIndex: 0})
};
onTimeUpdate = () => {
let currentTime = this.refs.audioDiv.currentTime;
currentTime = getTime(Math.floor(currentTime));
this.setState({progressIndex: currentTime})
};
}
Upvotes: 1