I was trying to create an app that loads videos from an ARRAY on loop. I am using UseState to change the URI index after the video ends.
The player works perfectly for around 1-2 hours then it freezes the video and throws onError() which gives player error null
and sometimes Player release time out.
I am thinking that it might be happening because of useState because it re-renders the component every time when index changes. Maybe this could be memory leakage or something else I am not sure.
please help me I seriously spent a week to find the solution. I even tried caching the videos using the filesystem. but still, it doesn't stop freezing.
const VideoPlayer = ({ wholeResult }) => {
const focuspoint = React.useRef(null);
const [index, setIndex] = React.useState(0);
const [progress, setProgress] = React.useState(false);
React.useEffect(() => {
if (wholeResult !== undefined) {
setProgress(true);
}
}, []);
const navigation = useNavigation();
return (
<View style={styles.container}>
<TouchableOpacity
onLongPress={() => {
navigation.navigate("Home");
}}
delayLongPress={3000}
>
{progress &&
wholeResult[index] !== "" &&
wholeResult[index] !== undefined
? <Video
ref={focuspoint}
style={styles.video}
source={{
uri: wholeResult.length == 1 ? wholeResult[0] : wholeResult[index],
}}
useNativeControls={false}
shouldPlay
resizeMode="stretch"
isLooping={wholeResult.length == 1 ? true : false}
onError={(error) =>
alert(error)
}
onPlaybackStatusUpdate={(status) =>
status?.didJustFinish == true
? setIndex((idx) => (idx == wholeResult.length - 1 ? 0 : idx + 1))
: null
}
/>
: null}
</TouchableOpacity>
</View>
);
};
export default VideoPlayer;
EDIT: I think this is the issue with expo-av only or it might be a bug with it. I tried with imageBackground and it's working is perfectly with the same pattern of code.
Answering my Own Question
So I couldn't find the solution to this problem but I got a trick to play, I used Webview to run Html containing a video looping function. But I have to use some parameters that could run in every device by enabling hardware acceleration. and it works for me.
<WebView
style={styles.container}
originWhitelist={["*"]}
allowFileAccess={true}
allowUniversalAccessFromFileURLs={true}
allowFileAccessFromFileURLs={true}
javaScriptEnabled={true}
domStorageEnabled={true}
allowsFullscreenVideo={true}
mixedContentMode='always'
androidLayerType="hardware"
androidHardwareAccelerationDisabled={false}
mediaPlaybackRequiresUserAction={false}
source={{
html: `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
<style>
body {
margin: 0;
padding: 0;
overflow: hidden;
box-sizing: border-box;
background: #000;
}
video {
width: 100vw;
height: 100vh;
object-fit: cover;
}
</style>
</head>
<body>
<video id="myVideo" autoplay muted></video>
<script>
var videoSource = new Array();
videoSource = ${JSON.stringify(vid)};
var videoCount = videoSource.length;
var elem = document.getElementById("myVideo");
if (elem.requestFullscreen) {
elem.requestFullscreen();
} else if (elem.mozRequestFullScreen) {
elem.mozRequestFullScreen();
} else if (elem.webkitRequestFullscreen) {
elem.webkitRequestFullscreen();
} else if (elem.msRequestFullscreen) {
elem.msRequestFullscreen();
}
document.getElementById("myVideo").setAttribute("src", videoSource[0]);
function videoPlay(videoNum) {
document
.getElementById("myVideo")
.setAttribute("src", videoSource[videoNum]);
document.getElementById("myVideo").load();
document.getElementById("myVideo").play();
}
document
.getElementById("myVideo")
.addEventListener("ended", myHandler, false);
var incr = (function () {
var i = 0;
return function () {
if (i > videoCount - 1) {
i = 0;
}
return i++;
};
})();
function myHandler() {
videoPlay(incr());
}
</script>
</body>
</html>
`,
}}
/>