UNPKG

react-native-vlc-media-player

Version:

React native media player for video streaming and playing. Supports RTSP,RTMP and other protocols supported by VLC player

561 lines (538 loc) 14.1 kB
/** * Created by yuanzhou.xu on 2018/5/14. */ import React, { Component } from 'react'; import { StyleSheet, Text, View, Dimensions, TouchableOpacity, ActivityIndicator, StatusBar, BackHandler, Modal, Platform, } from 'react-native'; import VLCPlayer from '../VLCPlayer'; import PropTypes from 'prop-types'; import TimeLimt from './TimeLimit'; import ControlBtn from './ControlBtn'; import Icon from 'react-native-vector-icons/MaterialCommunityIcons'; import { getStatusBarHeight } from './SizeController'; const statusBarHeight = getStatusBarHeight(); let deviceHeight = Dimensions.get('window').height; let deviceWidth = Dimensions.get('window').width; export default class VLCPlayerView extends Component { static propTypes = { uri: PropTypes.string, }; constructor(props) { super(props); this.state = { paused: true, isLoading: true, loadingSuccess: false, isFull: false, currentTime: 0.0, totalTime: 0.0, showControls: false, seek: 0, isError: false, }; this.touchTime = 0; this.changeUrl = false; this.isEnding = false; this.reloadSuccess = false; } static defaultProps = { initPaused: false, source: null, seek: 0, playInBackground: false, isGG: false, autoplay: true, errorTitle: 'Error play video, please try again' }; componentDidMount() { if (this.props.isFull) { this.setState({ showControls: true, }); } } componentWillUnmount() { this.vlcPlayer._onStopped() if (this.bufferInterval) { clearInterval(this.bufferInterval); this.bufferInterval = null; } } componentDidUpdate(prevProps, prevState) { if (this.props.uri !== prevProps.uri) { console.log("componentDidUpdate"); this.changeUrl = true; } } render() { let { onEnd, style, isGG, type, isFull, uri, title, onLeftPress, closeFullScreen, showBack, showTitle, videoAspectRatio, showGoLive, onGoLivePress, onReplayPress, titleGolive, showLeftButton, showMiddleButton, showRightButton, errorTitle } = this.props; let { isLoading, loadingSuccess, showControls, isError } = this.state; let showGG = false; let realShowLoding = false; let source = {}; if (uri) { if (uri.split) { source = { uri: this.props.uri }; } else { source = uri; } } if (Platform.OS === 'ios') { if ((loadingSuccess && isGG) || (isGG && type === 'swf')) { showGG = true; } if (isLoading && type !== 'swf') { realShowLoding = true; } } else { if (loadingSuccess && isGG) { showGG = true; } if (isLoading) { realShowLoding = true; } } return ( <TouchableOpacity activeOpacity={1} style={[styles.videoBtn, style]} onPressOut={() => { let currentTime = new Date().getTime(); if (this.touchTime === 0) { this.touchTime = currentTime; this.setState({ showControls: !this.state.showControls }); } else { if (currentTime - this.touchTime >= 500) { this.touchTime = currentTime; this.setState({ showControls: !this.state.showControls }); } } }}> <VLCPlayer ref={ref => (this.vlcPlayer = ref)} paused={this.state.paused} //seek={this.state.seek} style={[styles.video]} source={source} videoAspectRatio={videoAspectRatio} onProgress={this.onProgress.bind(this)} onEnd={this.onEnded.bind(this)} //onEnded={this.onEnded.bind(this)} onStopped={this.onEnded.bind(this)} onPlaying={this.onPlaying.bind(this)} onBuffering={this.onBuffering.bind(this)} onPaused={this.onPaused.bind(this)} progressUpdateInterval={250} onError={this._onError} onOpen={this._onOpen} onLoadStart={this._onLoadStart} /> {realShowLoding && !isError && ( <View style={styles.loading}> <ActivityIndicator size={'large'} animating={true} color="#fff" /> </View> )} {isError && ( <View style={[styles.loading, { backgroundColor: '#000' }]}> <Text style={{ color: 'red' }}>{errorTitle}</Text> <TouchableOpacity activeOpacity={1} onPress={this._reload} style={{ width: 100, alignItems: 'center', justifyContent: 'center', marginTop: 10, }}> <Icon name={'reload'} size={45} color="#fff" /> </TouchableOpacity> </View> )} <View style={styles.topView}> <View style={styles.backBtn}> {showBack && ( <TouchableOpacity onPress={() => { if (isFull) { closeFullScreen && closeFullScreen(); } else { onLeftPress && onLeftPress(); } }} style={styles.btn} activeOpacity={0.8}> <Icon name={'chevron-left'} size={30} color="#fff" /> </TouchableOpacity> )} <View style={{ justifyContent: 'center', flex: 1, marginRight: 10 }}> {showTitle && showControls && ( <Text style={{ color: '#fff', fontSize: 16 }} numberOfLines={1}> {title} </Text> )} </View> {showGG && ( <View style={styles.GG}> <TimeLimt onEnd={() => { onEnd && onEnd(); }} //maxTime={Math.ceil(this.state.totalTime)} /> </View> )} </View> </View> <View style={[styles.bottomView]}> {showControls && ( <ControlBtn //style={isFull?{width:deviceHeight}:{}} showSlider={!isGG} showGG={showGG} onEnd={onEnd} title={title} onLeftPress={onLeftPress} paused={this.state.paused} isFull={isFull} currentTime={this.state.currentTime} totalTime={this.state.totalTime} onPausedPress={this._play} onFullPress={this._toFullScreen} onValueChange={value => { this.changingSlider = true; this.setState({ currentTime: value, }); }} onSlidingComplete={value => { this.changingSlider = false; if (Platform.OS === 'ios') { this.vlcPlayer.seek(Number((value / this.state.totalTime).toFixed(17))); } else { this.vlcPlayer.seek(value); } }} showGoLive={showGoLive} onGoLivePress={onGoLivePress} onReplayPress={onReplayPress} titleGolive={titleGolive} showLeftButton={showLeftButton} showMiddleButton={showMiddleButton} showRightButton={showRightButton} /> )} </View> </TouchableOpacity> ); } /** * 视屏播放 * @param event */ onPlaying(event) { this.isEnding = false; // if (this.state.paused) { // this.setState({ paused: false }); // } console.log('onPlaying'); } /** * 视屏停止 * @param event */ onPaused(event) { // if (!this.state.paused) { // this.setState({ paused: true, showControls: true }); // } else { // this.setState({ showControls: true }); // } console.log('onPaused'); } /** * 视屏缓冲 * @param event */ onBuffering(event) { this.setState({ isLoading: true, isError: false, }); this.bufferTime = new Date().getTime(); if (!this.bufferInterval) { this.bufferInterval = setInterval(this.bufferIntervalFunction, 250); } console.log('onBuffering'); console.log(event); } bufferIntervalFunction = () => { console.log('bufferIntervalFunction'); let currentTime = new Date().getTime(); let diffTime = currentTime - this.bufferTime; if (diffTime > 1000) { clearInterval(this.bufferInterval); this.setState({ paused: true, }, () => { this.setState({ paused: false, isLoading: false, }); }); this.bufferInterval = null; console.log('remove bufferIntervalFunction'); } }; _onError = e => { // [bavv add start] let { onVLCError } = this.props; onVLCError && onVLCError(); // [bavv add end] console.log('_onError'); console.log(e); this.reloadSuccess = false; this.setState({ isError: true, }); }; _onOpen = e => { console.log('onOpen', e); }; _onLoadStart = e => { console.log('_onLoadStart'); console.log(e); let { isError } = this.state; if (isError) { this.reloadSuccess = true; let { currentTime, totalTime } = this.state; if (Platform.OS === 'ios') { this.vlcPlayer.seek(Number((currentTime / totalTime).toFixed(17))); } else { this.vlcPlayer.seek(currentTime); } this.setState({ paused: true, isError: false, }, () => { this.setState({ paused: false, }); }) } else { this.vlcPlayer.seek(0); this.setState({ isLoading: true, isError: false, loadingSuccess: false, paused: true, currentTime: 0.0, totalTime: 0.0, }, () => { this.setState({ paused: false, }); }) } }; _reload = () => { if (!this.reloadSuccess) { this.vlcPlayer.resume && this.vlcPlayer.resume(false); } }; /** * 视屏进度变化 * @param event */ onProgress(event) { /* console.log( 'position=' + event.position + ',currentTime=' + event.currentTime + ',remainingTime=' + event.remainingTime, );*/ let currentTime = event.currentTime; let loadingSuccess = false; if (currentTime > 0 || this.state.currentTime > 0) { loadingSuccess = true; } if (!this.changingSlider) { if (currentTime === 0 || currentTime === this.state.currentTime * 1000) { } else { this.setState({ loadingSuccess: loadingSuccess, isLoading: false, isError: false, progress: event.position, currentTime: event.currentTime / 1000, totalTime: event.duration / 1000, }); } } } /** * 视屏播放结束 * @param event */ onEnded(event) { console.log('onEnded ---------->') console.log(event) console.log('<---------- onEnded ') let { currentTime, totalTime } = this.state; // [bavv add start] let { onVLCEnded, onEnd, autoplay, isGG } = this.props; onVLCEnded && onVLCEnded(); // [bavv add end] if (((currentTime + 5) >= totalTime && totalTime > 0) || isGG) { this.setState( { paused: true, //showControls: true, }, () => { if (!this.isEnding) { onEnd && onEnd(); if (!isGG) { this.vlcPlayer.resume && this.vlcPlayer.resume(false); console.log(this.props.uri + ': onEnded'); } else { console.log('片头:' + this.props.uri + ': onEnded'); } this.isEnding = true; } }, ); } else { /* console.log('onEnded error:'+this.props.uri); this.vlcPlayer.resume && this.vlcPlayer.resume(false);*/ /*this.setState({ paused: true, },()=>{ console.log('onEnded error:'+this.props.uri); this.reloadSuccess = false; this.setState({ isError: true, }); });*/ } } /** * 全屏 * @private */ _toFullScreen = () => { let { startFullScreen, closeFullScreen, isFull } = this.props; if (isFull) { closeFullScreen && closeFullScreen(); } else { startFullScreen && startFullScreen(); } }; /** * 播放/停止 * @private */ _play = () => { this.setState({ paused: !this.state.paused }); }; } const styles = StyleSheet.create({ container: { flex: 1, }, videoBtn: { flex: 1, }, video: { justifyContent: 'center', alignItems: 'center', height: '100%', width: '100%', }, loading: { position: 'absolute', left: 0, top: 0, zIndex: 0, width: '100%', height: '100%', justifyContent: 'center', alignItems: 'center', }, GG: { backgroundColor: 'rgba(255,255,255,1)', height: 30, marginRight: 10, paddingLeft: 10, paddingRight: 10, borderRadius: 20, justifyContent: 'center', alignItems: 'center', }, topView: { top: Platform.OS === 'ios' ? statusBarHeight : 0, left: 0, height: 45, position: 'absolute', width: '100%', //backgroundColor: 'red' }, bottomView: { bottom: 0, left: 0, height: 50, position: 'absolute', width: '100%', backgroundColor: 'rgba(0,0,0,0)', }, backBtn: { height: 45, width: '100%', flexDirection: 'row', alignItems: 'center', }, btn: { marginLeft: 10, marginRight: 10, justifyContent: 'center', alignItems: 'center', backgroundColor: 'rgba(0,0,0,0.3)', height: 40, borderRadius: 20, width: 40, paddingTop: 3, }, });