import React, { Component, PureComponent } from 'react';
import PropTypes from 'prop-types';
import flvjs from 'flv.js';
import waiting from '@/assets/waiting.jpg';
/**
* react component wrap flv.js
*/
export default class Reflv extends PureComponent<any, any> {
static propTypes = {
className: PropTypes.string,
style: PropTypes.object,
/**
* media URL, can be starts with 'https(s)' or 'ws(s)' (WebSocket)
*/
url: PropTypes.string,
/**
* media type, 'flv' or 'mp4'
*/
type: PropTypes.oneOf(['flv', 'mp4']).isRequired,
/**
* whether the data source is a **live stream**
*/
isLive: PropTypes.bool,
/**
* whether to enable CORS for http fetching
*/
cors: PropTypes.bool,
/**
* whether to do http fetching with cookies
*/
withCredentials: PropTypes.bool,
/**
* whether the stream has audio track
*/
hasAudio: PropTypes.bool,
/**
* whether the stream has video track
*/
hasVideo: PropTypes.bool,
/**
* total media duration, in milliseconds
*/
duration: PropTypes.bool,
/**
* total file size of media file, in bytes
*/
filesize: PropTypes.number,
/**
* Optional field for multipart playback, see MediaSegment
*/
segments: PropTypes.arrayOf(
PropTypes.shape({
/**
* indicates segment duration in milliseconds
*/
duration: PropTypes.number.isRequired,
/**
* indicates segment file size in bytes
*/
filesize: PropTypes.number,
/**
* indicates segment file URL
*/
url: PropTypes.string.isRequired,
}),
),
/**
* @see https://github.com/Bilibili/flv.js/blob/master/docs/api.md#config
*/
config: PropTypes.object,
};
init = () => {
let $video = this.inputRef;
if ($video) {
if (flvjs.isSupported()) {
const {
url,
type,
isLive,
cors,
hasAudio = false,
} = this.props;
let player = flvjs.createPlayer(
{
url,
type,
isLive,
hasAudio,
cors,
},
this.props.config || {
enableStashBuffer: false, // 关闭IO隐藏缓冲区
stashInitialSize: 128, // 减少首帧显示等待时长
},
);
player.attachMediaElement($video);
player.load();
if (this.props.autoPlay) {
player.play();
}
this.player = player;
}
}
};
inputRef: any;
player: any;
componentWillUnmount() {
if (this.player) {
this.player.unload();
this.player.detachMediaElement();
}
}
componentWillReceiveProps(nextProps: any, nextState: any) {
}
componentDidUpdate(prevProps: Readonly<any>, prevState: Readonly<any>, snapshot?: any): void {
if (prevProps.url != this.props.url||prevProps.type != this.props.type) {
this.destroyFlv();
this.init();
}
}
destroyFlv = () => {
if (this.player) {
this.player.pause();
this.player.unload();
this.player.detachMediaElement();
this.player.destroy();
this.player = null;
}
};
listenVideoErr = () => {
const that = this;
this.player.on(flvjs.Events.ERROR, (errorType, errorDetail, errorInfo) => {
console.log('触发了错误')
try {
console.log('errorType', errorType);
console.log('errorDetail', errorDetail);
console.log('errorInfo', errorInfo);
// 视频出错后销毁重建
that.player.unload();
that.player.load();
if (that.props.autoPlay) {
that.player.play();
}
} catch { }
});
};
listenVideoErrStatic = () => {
const that = this;
// 视频断流
this.player.on('statistics_info', function (res) {
if (that.state.lastDecodedFrames === 0) {
that.setState({ lastDecodedFrames: res.decodedFrames });
console.log('触发了视频断流1')
return;
}
if (that.state.lastDecodedFrames != res.decodedFrames) {
that.setState({ lastDecodedFrames: res.decodedFrames });
} else {
console.log('触发了视频断流销毁')
that.setState({ lastDecodedFrames: 0 });
that.player.unload(); // 卸载当前视频源
that.player.load();
}
});
}
constructor(props: any) {
super(props);
this.state = {
lastDecodedFrames: 0,
};
}
componentDidMount(): void {
this.init();
this.listenVideoErr();
//this.listenVideoErrStatic();
}
render() {
const { className, style } = this.props;
return (
<video
autoPlay={this.props.autoPlay}
className={className}
controls={true}
poster={waiting}
style={Object.assign(
{
width: this.props.width,
height: this.props.height,
},
style,
)}
ref={(el) => {
this.inputRef = el;
}}
muted={this.props.autoPlay}
/>
);
}
}
react 封装一个flvjs
于 2023-07-21 13:54:49 首次发布