2015-12-06 23:25:18 -07:00
'use strict' ;
2023-10-07 15:14:09 -06:00
import React , { Component } from 'react' ;
2016-04-21 22:01:44 -06:00
import {
2015-12-06 23:25:18 -07:00
StyleSheet ,
Text ,
TouchableOpacity ,
2016-02-10 04:39:54 -07:00
View ,
2022-04-26 14:59:04 -06:00
ActivityIndicator ,
PanResponder ,
ToastAndroid ,
2023-10-07 15:14:09 -06:00
Platform ,
PanResponderInstance ,
Alert ,
2016-02-10 04:39:54 -07:00
} from 'react-native' ;
2023-10-07 15:14:09 -06:00
import { Picker } from '@react-native-picker/picker' ;
2022-04-26 14:59:04 -06:00
2023-10-26 00:46:04 -06:00
import Video , {
AudioTrack ,
OnAudioTracksData ,
OnLoadData ,
OnProgressData ,
OnTextTracksData ,
OnVideoAspectRatioData ,
TextTrack ,
VideoDecoderProperties ,
OnBufferData ,
OnAudioFocusChangedData ,
OnVideoErrorData ,
VideoRef ,
2023-11-22 07:03:57 -07:00
ResizeMode ,
SelectedTrack ,
2023-12-08 03:58:00 -07:00
DRMType ,
2024-02-29 06:41:04 -07:00
OnTextTrackDataChangedData ,
2024-03-30 05:22:37 -06:00
TextTrackType ,
ISO639_1 ,
2023-10-26 00:46:04 -06:00
} from 'react-native-video' ;
2023-10-07 15:14:09 -06:00
import ToggleControl from './ToggleControl' ;
2023-11-22 07:03:57 -07:00
import MultiValueControl , {
MultiValueControlPropType ,
} from './MultiValueControl' ;
interface StateType {
rate : number ;
volume : number ;
muted : boolean ;
resizeMode : ResizeMode ;
duration : number ;
currentTime : number ;
videoWidth : number ;
videoHeight : number ;
paused : boolean ;
fullscreen : true ;
decoration : true ;
isLoading : boolean ;
seekerFillWidth : number ;
seekerPosition : number ;
seekerOffset : number ;
seeking : boolean ;
audioTracks : Array < AudioTrack > ;
textTracks : Array < TextTrack > ;
selectedAudioTrack : SelectedTrack | undefined ;
selectedTextTrack : SelectedTrack | undefined ;
srcListId : number ;
loop : boolean ;
showRNVControls : boolean ;
}
2016-02-10 04:39:54 -07:00
class VideoPlayer extends Component {
2023-11-22 07:03:57 -07:00
state : StateType = {
2016-02-10 04:39:54 -07:00
rate : 1 ,
volume : 1 ,
muted : false ,
2023-10-26 00:46:04 -06:00
resizeMode : ResizeMode.CONTAIN ,
2016-02-10 04:39:54 -07:00
duration : 0.0 ,
currentTime : 0.0 ,
2022-04-26 14:59:04 -06:00
videoWidth : 0 ,
videoHeight : 0 ,
2022-04-23 14:54:34 -06:00
paused : false ,
2022-04-26 14:59:04 -06:00
fullscreen : true ,
decoration : true ,
isLoading : false ,
seekerFillWidth : 0 ,
seekerPosition : 0 ,
seekerOffset : 0 ,
seeking : false ,
audioTracks : [ ] ,
textTracks : [ ] ,
selectedAudioTrack : undefined ,
selectedTextTrack : undefined ,
srcListId : 0 ,
loop : false ,
2022-09-11 09:01:53 -06:00
showRNVControls : false ,
2016-02-10 04:39:54 -07:00
} ;
2015-12-06 23:25:18 -07:00
2023-10-07 15:14:09 -06:00
seekerWidth = 0 ;
2022-04-26 14:59:04 -06:00
2023-10-07 15:14:09 -06:00
srcAllPlatformList = [
2024-03-13 01:23:11 -06:00
{
description : 'local file' ,
uri : require ( './broadchurch.mp4' ) ,
} ,
2023-10-07 15:14:09 -06:00
{
description : '(hls|live) red bull tv' ,
uri : 'https://rbmn-live.akamaized.net/hls/live/590964/BoRB-AT/master_928.m3u8' ,
} ,
{
description : 'invalid URL' ,
uri : 'mmt://www.youtube.com' ,
type : 'mpd' ,
} ,
{ description : '(no url) Stopped playback' , uri : undefined } ,
{
description : '(no view) no View' ,
noView : true ,
} ,
{
description : 'Another live sample' ,
uri : 'https://live.forstreet.cl/live/livestream.m3u8' ,
} ,
2023-11-13 13:36:16 -07:00
{
description : 'another bunny (can be saved)' ,
2023-11-22 07:03:57 -07:00
uri : 'https://rawgit.com/mediaelement/mediaelement-files/master/big_buck_bunny.mp4' ,
} ,
2024-02-29 06:41:04 -07:00
{
description : 'sintel with subtitles' ,
uri : 'https://bitmovin-a.akamaihd.net/content/sintel/hls/playlist.m3u8' ,
} ,
2024-03-30 05:22:37 -06:00
{
description : 'sintel with sideLoaded subtitles' ,
uri : 'https://demo.unified-streaming.com/k8s/features/stable/video/tears-of-steel/tears-of-steel.ism/.m3u8' , // this is sample video, my actual video file is MP4
textTracks : [
{
title : 'test' ,
language : 'en' as ISO639_1 ,
type : TextTrackType . VTT ,
uri : 'https://bitdash-a.akamaihd.net/content/sintel/subtitles/subtitles_en.vtt' ,
} ,
]
} ,
2024-02-29 06:41:04 -07:00
] ;
2023-10-07 15:14:09 -06:00
2024-03-11 06:50:19 -06:00
srcIosList = [ ] ;
2023-10-07 15:14:09 -06:00
srcAndroidList = [
{
description : 'Another live sample' ,
uri : 'https://live.forstreet.cl/live/livestream.m3u8' ,
} ,
2022-05-19 07:29:25 -06:00
{
2022-06-03 13:51:53 -06:00
description : '(dash) sintel subtitles' ,
2022-05-19 07:29:25 -06:00
uri : 'https://bitmovin-a.akamaihd.net/content/sintel/sintel.mpd' ,
} ,
2022-04-26 14:59:04 -06:00
{
2022-06-03 13:51:53 -06:00
description : '(mp4) big buck bunny' ,
uri : 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4' ,
} ,
{
description : '(mp4|subtitles) demo with sintel Subtitles' ,
2023-10-07 15:14:09 -06:00
uri : 'http://www.youtube.com/api/manifest/dash/id/bf5bb2419360daf1/source/youtube?as=fmp4_audio_clear,fmp4_sd_hd_clear&sparams=ip,ipbits,expire,source,id,as&ip=0.0.0.0&ipbits=0&expire=19000000000&signature=51AF5F39AB0CEC3E5497CD9C900EBFEAECCCB5C7.8506521BFC350652163895D4C26DEE124209AA9E&key=ik0' ,
2022-09-14 13:58:59 -06:00
type : 'mpd' ,
} ,
2022-04-26 14:59:04 -06:00
{
2023-10-07 15:14:09 -06:00
description : '(mp4) big buck bunny With Ads' ,
adTagUrl :
'https://pubads.g.doubleclick.net/gampad/ads?iu=/21775744923/external/vmap_ad_samples&sz=640x480&cust_params=sample_ar%3Dpremidpostoptimizedpodbumper&ciu_szs=300x250&gdfp_req=1&ad_rule=1&output=vmap&unviewed_position_start=1&env=vp&impl=s&cmsid=496&vid=short_onecue&correlator=' ,
uri : 'http://d23dyxeqlo5psv.cloudfront.net/big_buck_bunny.mp4' ,
2022-04-26 14:59:04 -06:00
} ,
2023-12-08 03:58:00 -07:00
{
description : 'WV: Secure SD & HD (cbcs,MP4,H264)' ,
uri : 'https://storage.googleapis.com/wvmedia/cbcs/h264/tears/tears_aes_cbcs.mpd' ,
drm : {
type : DRMType . WIDEVINE ,
licenseServer :
'https://proxy.uat.widevine.com/proxy?provider=widevine_test' ,
} ,
} ,
{
description : 'Secure UHD (cenc)' ,
uri : 'https://storage.googleapis.com/wvmedia/cenc/h264/tears/tears_uhd.mpd' ,
drm : {
type : DRMType . WIDEVINE ,
licenseServer :
'https://proxy.uat.widevine.com/proxy?provider=widevine_test' ,
} ,
} ,
2023-10-07 15:14:09 -06:00
] ;
2022-04-26 14:59:04 -06:00
2023-10-07 15:14:09 -06:00
srcList = this . srcAllPlatformList . concat (
2023-11-22 07:03:57 -07:00
Platform . OS === 'android' ? this . srcAndroidList : this.srcIosList ,
2023-10-07 15:14:09 -06:00
) ;
2023-10-26 00:46:04 -06:00
video? : VideoRef ;
2023-10-07 15:14:09 -06:00
seekPanResponder? : PanResponderInstance ;
2015-12-06 23:25:18 -07:00
2022-06-23 14:54:47 -06:00
popupInfo = ( ) = > {
VideoDecoderProperties . getWidevineLevel ( ) . then ( ( widevineLevel : number ) = > {
2023-09-25 00:30:08 -06:00
VideoDecoderProperties . isHEVCSupported ( ) . then ( ( hevc : string ) = > {
2022-06-23 14:54:47 -06:00
VideoDecoderProperties . isCodecSupported ( 'video/avc' , 1920 , 1080 ) . then (
2023-09-25 00:30:08 -06:00
( avc : string ) = > {
2022-06-23 14:54:47 -06:00
this . toast (
true ,
'Widevine level: ' +
2023-11-22 07:03:57 -07:00
widevineLevel +
'\n hevc: ' +
hevc +
'\n avc: ' +
avc ,
2023-09-25 00:30:08 -06:00
) ;
2022-06-23 14:54:47 -06:00
} ,
2023-09-25 00:30:08 -06:00
) ;
} ) ;
} ) ;
} ;
2022-06-23 14:54:47 -06:00
2023-10-26 00:46:04 -06:00
onLoad = ( data : OnLoadData ) = > {
2023-10-07 15:14:09 -06:00
this . setState ( { duration : data.duration , loading : false } ) ;
this . onAudioTracks ( data ) ;
this . onTextTracks ( data ) ;
2017-01-11 05:51:45 -07:00
} ;
2023-10-26 00:46:04 -06:00
onProgress = ( data : OnProgressData ) = > {
2022-04-26 14:59:04 -06:00
if ( ! this . state . seeking ) {
2023-10-07 15:14:09 -06:00
const position = this . calculateSeekerPosition ( ) ;
this . setSeekerPosition ( position ) ;
2022-04-26 14:59:04 -06:00
}
2023-10-07 15:14:09 -06:00
this . setState ( { currentTime : data.currentTime } ) ;
2017-01-11 05:51:45 -07:00
} ;
2022-04-26 14:59:04 -06:00
onVideoLoadStart = ( ) = > {
2023-10-07 15:14:09 -06:00
console . log ( 'onVideoLoadStart' ) ;
this . setState ( { isLoading : true } ) ;
} ;
2022-04-26 14:59:04 -06:00
2023-10-26 00:46:04 -06:00
onAudioTracks = ( data : OnAudioTracksData ) = > {
const selectedTrack = data . audioTracks ? . find ( ( x : AudioTrack ) = > {
2023-10-07 15:14:09 -06:00
return x . selected ;
} ) ;
2022-04-26 14:59:04 -06:00
if ( selectedTrack ? . language ) {
this . setState ( {
2024-03-22 00:58:09 -06:00
audioTracks : data.audioTracks ,
2022-04-26 14:59:04 -06:00
selectedAudioTrack : {
type : 'language' ,
value : selectedTrack?.language ,
} ,
2023-10-07 15:14:09 -06:00
} ) ;
2024-03-22 00:58:09 -06:00
} else {
this . setState ( {
audioTracks : data.audioTracks ,
} ) ;
2022-04-26 14:59:04 -06:00
}
2023-10-07 15:14:09 -06:00
} ;
2022-04-26 14:59:04 -06:00
2023-10-26 00:46:04 -06:00
onTextTracks = ( data : OnTextTracksData ) = > {
const selectedTrack = data . textTracks ? . find ( ( x : TextTrack ) = > {
2024-02-29 06:41:04 -07:00
return x ? . selected ;
2023-10-07 15:14:09 -06:00
} ) ;
2022-04-26 14:59:04 -06:00
if ( selectedTrack ? . language ) {
this . setState ( {
2024-03-22 00:58:09 -06:00
textTracks : data.textTracks ,
2022-04-26 14:59:04 -06:00
selectedTextTrack : {
type : 'language' ,
value : selectedTrack?.language ,
} ,
2023-10-07 15:14:09 -06:00
} ) ;
2024-03-22 00:58:09 -06:00
} else {
this . setState ( {
textTracks : data.textTracks ,
} ) ;
2022-04-26 14:59:04 -06:00
}
2023-10-07 15:14:09 -06:00
} ;
2022-04-26 14:59:04 -06:00
2024-02-29 06:41:04 -07:00
onTextTrackDataChanged = ( data : OnTextTrackDataChangedData ) = > {
console . log ( ` Subtitles: ${ JSON . stringify ( data , null , 2 ) } ` ) ;
} ;
2023-10-26 00:46:04 -06:00
onAspectRatio = ( data : OnVideoAspectRatioData ) = > {
2023-10-07 15:14:09 -06:00
console . log ( 'onAspectRadio called ' + JSON . stringify ( data ) ) ;
2022-04-26 14:59:04 -06:00
this . setState ( {
videoWidth : data.width ,
videoHeight : data.height ,
2023-10-07 15:14:09 -06:00
} ) ;
} ;
2022-04-26 14:59:04 -06:00
2023-10-26 00:46:04 -06:00
onVideoBuffer = ( param : OnBufferData ) = > {
2023-10-07 15:14:09 -06:00
console . log ( 'onVideoBuffer' ) ;
this . setState ( { isLoading : param.isBuffering } ) ;
} ;
2022-04-26 14:59:04 -06:00
onReadyForDisplay = ( ) = > {
2023-10-07 15:14:09 -06:00
console . log ( 'onReadyForDisplay' ) ;
this . setState ( { isLoading : false } ) ;
} ;
2017-01-11 05:51:45 -07:00
onAudioBecomingNoisy = ( ) = > {
2023-10-07 15:14:09 -06:00
this . setState ( { paused : true } ) ;
2017-01-11 05:51:45 -07:00
} ;
2023-10-26 00:46:04 -06:00
onAudioFocusChanged = ( event : OnAudioFocusChangedData ) = > {
2023-10-07 15:14:09 -06:00
this . setState ( { paused : ! event . hasAudioFocus } ) ;
2017-01-11 05:51:45 -07:00
} ;
2015-12-06 23:25:18 -07:00
2022-04-26 14:59:04 -06:00
getCurrentTimePercentage = ( ) = > {
2022-04-23 14:23:10 -06:00
if ( this . state . currentTime > 0 && this . state . duration !== 0 ) {
return this . state . currentTime / this . state . duration ;
2015-12-06 23:25:18 -07:00
}
2017-01-11 05:51:45 -07:00
return 0 ;
} ;
2015-12-06 23:25:18 -07:00
2022-04-26 14:59:04 -06:00
toast = ( visible : boolean , message : string ) = > {
if ( visible ) {
2023-10-07 15:14:09 -06:00
if ( Platform . OS === 'android' ) {
ToastAndroid . showWithGravityAndOffset (
message ,
ToastAndroid . LONG ,
ToastAndroid . BOTTOM ,
25 ,
50 ,
) ;
} else {
Alert . alert ( message , message ) ;
}
2022-04-26 14:59:04 -06:00
}
2023-10-07 15:14:09 -06:00
} ;
2022-04-26 14:59:04 -06:00
2023-10-26 00:46:04 -06:00
onError = ( err : OnVideoErrorData ) = > {
console . log ( JSON . stringify ( err ) ) ;
this . toast ( true , 'error: ' + JSON . stringify ( err ) ) ;
2023-10-07 15:14:09 -06:00
} ;
2022-04-26 14:59:04 -06:00
onEnd = ( ) = > {
2023-10-07 15:14:09 -06:00
this . channelUp ( ) ;
2022-04-26 14:59:04 -06:00
} ;
toggleFullscreen() {
2023-10-07 15:14:09 -06:00
this . setState ( { fullscreen : ! this . state . fullscreen } ) ;
2022-04-26 14:59:04 -06:00
}
2022-09-11 09:01:53 -06:00
toggleControls() {
2023-10-07 15:14:09 -06:00
this . setState ( { showRNVControls : ! this . state . showRNVControls } ) ;
2022-09-11 09:01:53 -06:00
}
2022-04-26 14:59:04 -06:00
toggleDecoration() {
2023-10-07 15:14:09 -06:00
this . setState ( { decoration : ! this . state . decoration } ) ;
2022-04-26 14:59:04 -06:00
if ( this . state . decoration ) {
2023-10-07 15:14:09 -06:00
this . video ? . dismissFullscreenPlayer ( ) ;
2022-04-26 14:59:04 -06:00
} else {
2023-10-07 15:14:09 -06:00
this . video ? . presentFullscreenPlayer ( ) ;
2022-04-26 14:59:04 -06:00
}
}
2023-11-22 07:03:57 -07:00
goToChannel ( channel : number ) {
2022-04-26 14:59:04 -06:00
this . setState ( {
srcListId : channel ,
duration : 0.0 ,
currentTime : 0.0 ,
videoWidth : 0 ,
videoHeight : 0 ,
isLoading : false ,
audioTracks : [ ] ,
textTracks : [ ] ,
selectedAudioTrack : undefined ,
selectedTextTrack : undefined ,
2023-10-07 15:14:09 -06:00
} ) ;
2022-04-26 14:59:04 -06:00
}
channelUp() {
2023-10-07 15:14:09 -06:00
console . log ( 'channel up' ) ;
this . goToChannel ( ( this . state . srcListId + 1 ) % this . srcList . length ) ;
2022-04-26 14:59:04 -06:00
}
channelDown() {
2023-10-07 15:14:09 -06:00
console . log ( 'channel down' ) ;
this . goToChannel (
( this . state . srcListId + this . srcList . length - 1 ) % this . srcList . length ,
) ;
2022-04-26 14:59:04 -06:00
}
componentDidMount() {
2023-10-07 15:14:09 -06:00
this . initSeekPanResponder ( ) ;
2022-04-26 14:59:04 -06:00
}
/ * *
* Render the seekbar and attach its handlers
* /
/ * *
* Constrain the location of the seeker to the
* min / max value based on how big the
* seeker is .
*
* @param { float } val position of seeker handle in px
* @return { float } constrained position of seeker handle in px
* /
constrainToSeekerMinMax ( val = 0 ) {
if ( val <= 0 ) {
2023-10-07 15:14:09 -06:00
return 0 ;
2022-04-26 14:59:04 -06:00
} else if ( val >= this . seekerWidth ) {
2023-10-07 15:14:09 -06:00
return this . seekerWidth ;
2022-04-26 14:59:04 -06:00
}
2023-10-07 15:14:09 -06:00
return val ;
2022-04-26 14:59:04 -06:00
}
/ * *
* Set the position of the seekbar ' s components
* ( both fill and handle ) according to the
* position supplied .
*
* @param { float } position position in px of seeker handle }
* /
setSeekerPosition ( position = 0 ) {
2023-10-07 15:14:09 -06:00
const state = this . state ;
position = this . constrainToSeekerMinMax ( position ) ;
2022-04-26 14:59:04 -06:00
2023-10-07 15:14:09 -06:00
state . seekerFillWidth = position ;
state . seekerPosition = position ;
2022-04-26 14:59:04 -06:00
if ( ! state . seeking ) {
2023-10-07 15:14:09 -06:00
state . seekerOffset = position ;
2022-04-26 14:59:04 -06:00
}
2023-10-07 15:14:09 -06:00
this . setState ( state ) ;
2022-04-26 14:59:04 -06:00
}
/ * *
* Calculate the position that the seeker should be
* at along its track .
*
* @return { float } position of seeker handle in px based on currentTime
* /
calculateSeekerPosition() {
2023-10-07 15:14:09 -06:00
const percent = this . state . currentTime / this . state . duration ;
return this . seekerWidth * percent ;
2022-04-26 14:59:04 -06:00
}
/ * *
* Return the time that the video should be at
* based on where the seeker handle is .
*
* @return { float } time in ms based on seekerPosition .
* /
calculateTimeFromSeekerPosition() {
2023-10-07 15:14:09 -06:00
const percent = this . state . seekerPosition / this . seekerWidth ;
return this . state . duration * percent ;
2022-04-26 14:59:04 -06:00
}
/ * *
* Get our seekbar responder going
* /
initSeekPanResponder() {
this . seekPanResponder = PanResponder . create ( {
// Ask to be the responder.
2023-10-07 15:14:09 -06:00
onStartShouldSetPanResponder : ( _evt , _gestureState ) = > true ,
onMoveShouldSetPanResponder : ( _evt , _gestureState ) = > true ,
2022-04-26 14:59:04 -06:00
/ * *
* When we start the pan tell the machine that we ' re
* seeking . This stops it from updating the seekbar
* position in the onProgress listener .
* /
2023-10-07 15:14:09 -06:00
onPanResponderGrant : ( evt , _gestureState ) = > {
const state = this . state ;
2022-04-26 14:59:04 -06:00
// this.clearControlTimeout()
2023-10-07 15:14:09 -06:00
const position = evt . nativeEvent . locationX ;
this . setSeekerPosition ( position ) ;
state . seeking = true ;
this . setState ( state ) ;
2022-04-26 14:59:04 -06:00
} ,
/ * *
* When panning , update the seekbar position , duh .
* /
onPanResponderMove : ( evt , gestureState ) = > {
2023-10-07 15:14:09 -06:00
const position = this . state . seekerOffset + gestureState . dx ;
this . setSeekerPosition ( position ) ;
2022-04-26 14:59:04 -06:00
} ,
/ * *
* On release we update the time and seek to it in the video .
* If you seek to the end of the video we fire the
* onEnd callback
* /
2023-10-07 15:14:09 -06:00
onPanResponderRelease : ( _evt , _gestureState ) = > {
const time = this . calculateTimeFromSeekerPosition ( ) ;
const state = this . state ;
2022-04-26 14:59:04 -06:00
if ( time >= state . duration && ! state . isLoading ) {
2023-10-07 15:14:09 -06:00
state . paused = true ;
this . onEnd ( ) ;
2022-04-26 14:59:04 -06:00
} else {
2023-10-07 15:14:09 -06:00
this . video ? . seek ( time ) ;
state . seeking = false ;
2022-04-26 14:59:04 -06:00
}
2023-10-07 15:14:09 -06:00
this . setState ( state ) ;
2022-04-26 14:59:04 -06:00
} ,
2023-10-07 15:14:09 -06:00
} ) ;
2022-04-26 14:59:04 -06:00
}
renderSeekBar() {
if ( ! this . seekPanResponder ) {
2023-10-07 15:14:09 -06:00
return null ;
2022-04-26 14:59:04 -06:00
}
2023-10-07 15:14:09 -06:00
const seekerStyle = [
styles . seekbarFill ,
{
width : this.state.seekerFillWidth > 0 ? this . state.seekerFillWidth : 0 ,
backgroundColor : '#FFF' ,
} ,
] ;
const seekerPositionStyle = [
styles . seekbarHandle ,
{
left : this.state.seekerPosition > 0 ? this . state.seekerPosition : 0 ,
} ,
] ;
const seekerPointerStyle = [
styles . seekbarCircle ,
{ backgroundColor : '#FFF' } ,
] ;
2022-04-26 14:59:04 -06:00
return (
< View
style = { styles . seekbarContainer }
{ . . . this . seekPanResponder . panHandlers }
2023-10-07 15:14:09 -06:00
{ . . . styles . generalControls } >
2022-04-26 14:59:04 -06:00
< View
style = { styles . seekbarTrack }
2023-10-07 15:14:09 -06:00
onLayout = { event = >
( this . seekerWidth = event . nativeEvent . layout . width )
}
pointerEvents = { 'none' } >
< View style = { seekerStyle } pointerEvents = { 'none' } / >
2022-04-26 14:59:04 -06:00
< / View >
2023-10-07 15:14:09 -06:00
< View style = { seekerPositionStyle } pointerEvents = { 'none' } >
< View style = { seekerPointerStyle } pointerEvents = { 'none' } / >
2022-04-26 14:59:04 -06:00
< / View >
< / View >
2023-10-07 15:14:09 -06:00
) ;
2022-04-26 14:59:04 -06:00
}
IndicatorLoadingView() {
2023-10-07 15:14:09 -06:00
if ( this . state . isLoading ) {
return (
< ActivityIndicator
color = "#3235fd"
size = "large"
style = { styles . IndicatorStyle }
/ >
) ;
} else {
return < View / > ;
}
2022-04-26 14:59:04 -06:00
}
2022-09-11 09:01:53 -06:00
renderTopControl() {
2023-10-07 15:14:09 -06:00
return (
< >
< Text style = { [ styles . controlOption ] } >
{ this . srcList [ this . state . srcListId ] ? . description || 'local file' }
< / Text >
< View >
< TouchableOpacity
onPress = { ( ) = > {
this . toggleControls ( ) ;
} } >
< Text style = { [ styles . leftRightControlOption ] } >
{ this . state . showRNVControls ? 'Hide controls' : 'Show controls' }
< / Text >
< / TouchableOpacity >
< / View >
< / >
) ;
2022-09-11 09:01:53 -06:00
}
2023-11-22 07:03:57 -07:00
onRateSelected = ( value : MultiValueControlPropType ) = > {
2023-10-07 15:14:09 -06:00
this . setState ( { rate : value } ) ;
2023-11-22 07:03:57 -07:00
} ;
onVolumeSelected = ( value : MultiValueControlPropType ) = > {
2023-10-07 15:14:09 -06:00
this . setState ( { volume : value } ) ;
2023-11-22 07:03:57 -07:00
} ;
onResizeModeSelected = ( value : MultiValueControlPropType ) = > {
2023-10-07 15:14:09 -06:00
this . setState ( { resizeMode : value } ) ;
2023-11-22 07:03:57 -07:00
} ;
2022-09-11 09:01:53 -06:00
2022-04-26 14:59:04 -06:00
renderOverlay() {
return (
< >
{ this . IndicatorLoadingView ( ) }
< View style = { styles . topControls } >
2023-10-07 15:14:09 -06:00
< View style = { styles . resizeModeControl } >
{ this . renderTopControl ( ) }
< / View >
2015-12-06 23:25:18 -07:00
< / View >
2022-09-11 09:01:53 -06:00
{ ! this . state . showRNVControls ? (
< >
< View style = { styles . leftControls } >
2023-10-07 15:14:09 -06:00
< ToggleControl
onPress = { ( ) = > {
this . channelDown ( ) ;
} }
2023-11-22 07:03:57 -07:00
text = "ChDown"
2023-10-07 15:14:09 -06:00
/ >
< / View >
< View style = { styles . rightControls } >
< ToggleControl
onPress = { ( ) = > {
this . channelUp ( ) ;
} }
2023-11-22 07:03:57 -07:00
text = "ChUp"
/ >
2023-10-07 15:14:09 -06:00
< / View >
< View style = { styles . bottomControls } >
2022-09-11 09:01:53 -06:00
< View style = { styles . generalControls } >
2023-10-07 15:14:09 -06:00
{ Platform . OS === 'android' ? (
< View style = { styles . generalControls } >
< ToggleControl
onPress = { ( ) = > {
this . popupInfo ( ) ;
} }
2023-11-22 07:03:57 -07:00
text = "decoderInfo"
2023-10-07 15:14:09 -06:00
/ >
2023-11-22 07:03:57 -07:00
< / View >
2023-10-07 15:14:09 -06:00
) : null }
< ToggleControl
isSelected = { this . state . paused }
onPress = { ( ) = > {
this . setState ( { paused : ! this . state . paused } ) ;
} }
2023-11-22 07:03:57 -07:00
selectedText = "pause"
unselectedText = "playing"
2023-10-07 15:14:09 -06:00
/ >
< ToggleControl
isSelected = { this . state . loop }
onPress = { ( ) = > {
this . setState ( { loop : ! this . state . loop } ) ;
} }
2023-11-22 07:03:57 -07:00
selectedText = "loop enable"
unselectedText = "loop disable"
2023-10-07 15:14:09 -06:00
/ >
< ToggleControl
onPress = { ( ) = > {
this . toggleFullscreen ( ) ;
} }
2023-11-22 07:03:57 -07:00
text = "fullscreen"
2023-10-07 15:14:09 -06:00
/ >
< ToggleControl
onPress = { ( ) = > {
this . toggleDecoration ( ) ;
} }
2023-11-22 07:03:57 -07:00
text = "decoration"
/ >
2022-09-11 09:01:53 -06:00
< / View >
< View style = { styles . generalControls } >
2024-03-21 08:40:25 -06:00
{ /* shall be replaced by slider */ }
2023-10-07 15:14:09 -06:00
< MultiValueControl
2024-03-21 08:40:25 -06:00
values = { [ 0 , 0.25 , 0.5 , 1.0 , 1.5 , 2.0 ] }
2023-10-07 15:14:09 -06:00
onPress = { this . onRateSelected }
selected = { this . state . rate }
/ >
2024-03-21 08:40:25 -06:00
{ /* shall be replaced by slider */ }
2023-10-07 15:14:09 -06:00
< MultiValueControl
values = { [ 0.5 , 1 , 1.5 ] }
onPress = { this . onVolumeSelected }
selected = { this . state . volume }
/ >
< MultiValueControl
2023-11-22 07:03:57 -07:00
values = { [
ResizeMode . COVER ,
ResizeMode . CONTAIN ,
ResizeMode . STRETCH ,
] }
2023-10-07 15:14:09 -06:00
onPress = { this . onResizeModeSelected }
selected = { this . state . resizeMode }
/ >
2023-12-10 07:53:48 -07:00
{ Platform . OS === 'ios' ? (
< ToggleControl
isSelected = { this . state . paused }
onPress = { ( ) = > {
this . video
? . save ( { } )
? . then ( response = > {
console . log ( 'Downloaded URI' , response ) ;
} )
. catch ( error = > {
console . log ( 'error during save ' , error ) ;
} ) ;
} }
text = "save"
/ >
) : null }
2022-09-11 09:01:53 -06:00
< / View >
{ this . renderSeekBar ( ) }
< View style = { styles . generalControls } >
< Text style = { styles . controlOption } > AudioTrack < / Text >
{ this . state . audioTracks ? . length <= 0 ? (
< Text style = { styles . controlOption } > empty < / Text >
) : (
< Picker
style = { styles . picker }
selectedValue = { this . state . selectedAudioTrack ? . value }
2023-11-22 07:03:57 -07:00
onValueChange = { itemValue = > {
2022-09-11 09:01:53 -06:00
console . log ( 'on audio value change ' + itemValue ) ;
this . setState ( {
selectedAudioTrack : {
type : 'language' ,
value : itemValue ,
} ,
} ) ;
2023-10-07 15:14:09 -06:00
} } >
{ this . state . audioTracks . map ( track = > {
2024-03-14 04:46:45 -06:00
if ( ! track ) {
return ;
}
2022-09-11 09:01:53 -06:00
return (
< Picker.Item
label = { track . language }
value = { track . language }
2023-10-07 15:14:09 -06:00
key = { track . language }
/ >
2022-09-11 09:01:53 -06:00
) ;
} ) }
< / Picker >
) }
< Text style = { styles . controlOption } > TextTrack < / Text >
{ this . state . textTracks ? . length <= 0 ? (
< Text style = { styles . controlOption } > empty < / Text >
) : (
< Picker
style = { styles . picker }
selectedValue = { this . state . selectedTextTrack ? . value }
2023-11-22 07:03:57 -07:00
onValueChange = { itemValue = > {
2022-09-11 09:01:53 -06:00
console . log ( 'on value change ' + itemValue ) ;
this . setState ( {
selectedTextTrack : {
type : 'language' ,
value : itemValue ,
} ,
} ) ;
2023-10-07 15:14:09 -06:00
} } >
2022-09-11 09:01:53 -06:00
< Picker.Item label = { 'none' } value = { 'none' } key = { 'none' } / >
2024-03-14 04:46:45 -06:00
{ this . state . textTracks . map ( track = > {
if ( ! track ) {
return ;
}
return (
< Picker.Item
label = { track . language }
value = { track . language }
key = { track . language }
/ >
) ;
} ) }
2022-09-11 09:01:53 -06:00
< / Picker >
) }
< / View >
2023-10-07 15:14:09 -06:00
< / View >
< / >
) : null }
2022-04-26 14:59:04 -06:00
< / >
2023-10-07 15:14:09 -06:00
) ;
2022-04-26 14:59:04 -06:00
}
renderVideoView() {
2023-10-07 15:14:09 -06:00
const viewStyle = this . state . fullscreen
? styles . fullScreen
: styles . halfScreen ;
2022-04-26 14:59:04 -06:00
return (
< TouchableOpacity style = { viewStyle } >
< Video
2023-10-26 00:46:04 -06:00
ref = { ( ref : VideoRef ) = > {
2023-10-07 15:14:09 -06:00
this . video = ref ;
2022-04-26 14:59:04 -06:00
} }
source = { this . srcList [ this . state . srcListId ] }
2024-03-30 05:22:37 -06:00
textTracks = { this . srcList [ this . state . srcListId ] ? . textTracks }
2023-11-24 05:17:13 -07:00
adTagUrl = { this . srcList [ this . state . srcListId ] ? . adTagUrl }
2023-12-08 03:58:00 -07:00
drm = { this . srcList [ this . state . srcListId ] ? . drm }
2022-04-26 14:59:04 -06:00
style = { viewStyle }
rate = { this . state . rate }
paused = { this . state . paused }
volume = { this . state . volume }
muted = { this . state . muted }
2022-11-03 01:26:31 -06:00
fullscreen = { this . state . fullscreen }
2022-09-11 09:01:53 -06:00
controls = { this . state . showRNVControls }
2022-04-26 14:59:04 -06:00
resizeMode = { this . state . resizeMode }
onLoad = { this . onLoad }
2022-08-06 04:09:35 -06:00
onAudioTracks = { this . onAudioTracks }
onTextTracks = { this . onTextTracks }
2024-02-29 06:41:04 -07:00
onTextTrackDataChanged = { this . onTextTrackDataChanged }
2022-04-26 14:59:04 -06:00
onProgress = { this . onProgress }
onEnd = { this . onEnd }
progressUpdateInterval = { 1000 }
onError = { this . onError }
onAudioBecomingNoisy = { this . onAudioBecomingNoisy }
onAudioFocusChanged = { this . onAudioFocusChanged }
onLoadStart = { this . onVideoLoadStart }
2023-11-22 07:03:57 -07:00
onAspectRatio = { this . onAspectRatio }
2022-04-26 14:59:04 -06:00
onReadyForDisplay = { this . onReadyForDisplay }
onBuffer = { this . onVideoBuffer }
repeat = { this . state . loop }
selectedTextTrack = { this . state . selectedTextTrack }
selectedAudioTrack = { this . state . selectedAudioTrack }
2022-10-29 07:20:36 -06:00
playInBackground = { false }
2024-03-22 02:17:00 -06:00
preventsDisplaySleepDuringVideoPlayback = { true }
2022-04-26 14:59:04 -06:00
/ >
< / TouchableOpacity >
2023-10-07 15:14:09 -06:00
) ;
2022-04-26 14:59:04 -06:00
}
render() {
return (
< View style = { styles . container } >
2023-10-07 15:14:09 -06:00
{ this . srcList [ this . state . srcListId ] ? . noView
? null
: this . renderVideoView ( ) }
2022-04-26 14:59:04 -06:00
{ this . renderOverlay ( ) }
2015-12-06 23:25:18 -07:00
< / View >
2023-10-07 15:14:09 -06:00
) ;
2015-12-06 23:25:18 -07:00
}
2016-02-10 04:39:54 -07:00
}
2015-12-06 23:25:18 -07:00
2016-02-10 04:39:54 -07:00
const styles = StyleSheet . create ( {
2015-12-06 23:25:18 -07:00
container : {
flex : 1 ,
justifyContent : 'center' ,
alignItems : 'center' ,
backgroundColor : 'black' ,
} ,
2022-04-26 14:59:04 -06:00
halfScreen : {
position : 'absolute' ,
top : 50 ,
left : 50 ,
bottom : 100 ,
right : 100 ,
} ,
2015-12-06 23:25:18 -07:00
fullScreen : {
position : 'absolute' ,
top : 0 ,
left : 0 ,
bottom : 0 ,
right : 0 ,
} ,
2022-04-26 14:59:04 -06:00
bottomControls : {
backgroundColor : 'transparent' ,
borderRadius : 5 ,
position : 'absolute' ,
bottom : 20 ,
left : 20 ,
right : 20 ,
} ,
leftControls : {
2017-01-11 05:51:45 -07:00
backgroundColor : 'transparent' ,
2015-12-06 23:25:18 -07:00
borderRadius : 5 ,
position : 'absolute' ,
2022-04-26 14:59:04 -06:00
top : 20 ,
2015-12-06 23:25:18 -07:00
bottom : 20 ,
left : 20 ,
2022-04-26 14:59:04 -06:00
} ,
rightControls : {
backgroundColor : 'transparent' ,
borderRadius : 5 ,
position : 'absolute' ,
top : 20 ,
bottom : 20 ,
2015-12-06 23:25:18 -07:00
right : 20 ,
} ,
2022-04-26 14:59:04 -06:00
topControls : {
backgroundColor : 'transparent' ,
borderRadius : 4 ,
position : 'absolute' ,
top : 20 ,
left : 20 ,
right : 20 ,
2015-12-06 23:25:18 -07:00
flex : 1 ,
flexDirection : 'row' ,
overflow : 'hidden' ,
2022-04-26 14:59:04 -06:00
paddingBottom : 10 ,
2015-12-06 23:25:18 -07:00
} ,
generalControls : {
flex : 1 ,
flexDirection : 'row' ,
borderRadius : 4 ,
overflow : 'hidden' ,
paddingBottom : 10 ,
} ,
rateControl : {
flex : 1 ,
flexDirection : 'row' ,
justifyContent : 'center' ,
} ,
volumeControl : {
flex : 1 ,
flexDirection : 'row' ,
justifyContent : 'center' ,
} ,
resizeModeControl : {
flex : 1 ,
flexDirection : 'row' ,
alignItems : 'center' ,
justifyContent : 'center' ,
} ,
2022-04-26 14:59:04 -06:00
leftRightControlOption : {
alignSelf : 'center' ,
fontSize : 11 ,
color : 'white' ,
padding : 10 ,
lineHeight : 12 ,
} ,
2015-12-06 23:25:18 -07:00
controlOption : {
alignSelf : 'center' ,
fontSize : 11 ,
2017-01-11 05:51:45 -07:00
color : 'white' ,
2015-12-06 23:25:18 -07:00
paddingLeft : 2 ,
paddingRight : 2 ,
lineHeight : 12 ,
} ,
2022-04-26 14:59:04 -06:00
IndicatorStyle : {
flex : 1 ,
justifyContent : 'center' ,
} ,
seekbarContainer : {
flex : 1 ,
flexDirection : 'row' ,
borderRadius : 4 ,
height : 30 ,
} ,
seekbarTrack : {
backgroundColor : '#333' ,
height : 1 ,
position : 'relative' ,
top : 14 ,
width : '100%' ,
} ,
seekbarFill : {
backgroundColor : '#FFF' ,
height : 1 ,
width : '100%' ,
} ,
seekbarHandle : {
position : 'absolute' ,
marginLeft : - 7 ,
height : 28 ,
width : 28 ,
} ,
seekbarCircle : {
borderRadius : 12 ,
position : 'relative' ,
top : 8 ,
left : 8 ,
height : 12 ,
width : 12 ,
} ,
picker : {
color : 'white' ,
2022-04-23 14:23:10 -06:00
flex : 1 ,
flexDirection : 'row' ,
justifyContent : 'center' ,
} ,
2015-12-06 23:25:18 -07:00
} ) ;
2023-10-07 15:14:09 -06:00
export default VideoPlayer ;