I am trying to develop a video player app with a list of videos. The current behavior of app is, on click of any record play a video with given seek position and after click on another record switch a video in a player with given seek position. It works properly for the very first time with 3 to 4 videos but after that, it freezes in playing. And interestingly it will start playing that freeze video after 5 to 7 minutes. I have used streaming HLS URL with 2 to 4 hours duration. I have used react native ExoPlayer.
I want my app plays videos without freezing on switching another video.
Which player are you experiencing the problem on:
I want to make sure I replicate your scenario. So there is a list with a bunch of items each has a different video. When you click on one video, it seeks to the position from the previous video? Does the previous video pause?
Actually, there is a list with a bunch of items each has a different video and its seek position. So whenever we click on any video it will play with its own given seek position.
We have only one player for all list of video. So all video plays with that one player only.
Ok, so you click on a thumbnail and it sets a new source for the video player.
One thing that might be the issue is you should not call seek until you receive the onLoad event for the new video. If that's not the problem, there must be some kind of bug that will require some investigation.
Yes right, we seek video after onLoad method of a video. So it plays well for the first 3 to 4 video. but after that, it starts freezing.
Ok check my Linked message and lmk there.
Someone else had a similar bug. I had a hard time fixing it because it took a lot of steps. The good news here is this should be pretty easy to get into the error state.
Okay, can you please provide me your linked message? It would be helpful for me.
I had gotten a message from Kresimir on LinkedIn, I thought that was you. It's not appropriate for posting here.
Ok let me talk to Kresimir. Thank you.
i face the same problem
I setup an example where I can cycle between 5 different videos and it seeks to a random position between 10 & 60 seconds after onLoad and it's working properly.
Can someone provide a code sample that easily reproduces this bug?
Fairly certain the issue is what's described at https://google.github.io/ExoPlayer/faqs.html under "Why do some MPEG-TS files fail to play?"
We will need to set flags for videos that don't have IDR keyframes. This behavior will also need to be configurable since there are performance issues and other drawbacks when these flags are enabled.
in android, it is not go into onLoad, always in onbuffer even if i reopen this.page
@marlti7 I've been working with @ervishu83's team to diagnose this. For them it appears to be an incorrectly configured HLS playlist.
Your problem sounds like it may be a video that's encoded without IDR keyframes. In that case, you either need to re-encode the video or pass special flags to ExoPlayer to workaround the issue. It's described here:
https://google.github.io/ExoPlayer/faqs.html#why-do-some-mpeg-ts-files-fail-to-play
I will post a branch for you to test with tomorrow and if it works, I'll figure out how to make it configurable and create a PR.
I think I am experiencing this as well with Android ExoPlayer. Buggy videos loaded in succession (or a single video loaded repeatedly) eventually blocks subsequent buggy video loads. Non-buggy videos will still load.
I'm guessing the a video is buggy is it's encoded without IDR keyframes, but I'm not sure. How can I tell if a video is encoded without IDR keyframes?
Here is a component to demonstrate the problem. It lets you play videos sequentially, and toggles between 2 lists of videos (bad/buggy vs good). Each time you request a new video, the Video component instance will be destroyed and re-created after a second.
Keep pressing "Next video" until it stops working. Then press "Swap video list" to load a non-buggy video and see that works.
Why is one set of videos buggy and the other not? (I did not encode these. Is there any way to analyze them?) (https://pp.tedcdn.com/vids/intro_00/v01/master.m3u8 is buggy vs https://hls.ted.com/talks/1377.m3u8 is not buggy)
Adjust maxVideoListIndex in your experiments to see if there's any difference when loading the same video over and over or loading different videos.
This component was tested as the root of the project, so no nesting of other views.
"react-native": "0.56.0",
"react-native-video": "^3.2.1",
import React, {
Component
} from 'react';
import {
TouchableOpacity,
View,
Text,
} from 'react-native';
import Video from 'react-native-video';
const videos = {
bad: [
'https://pp.tedcdn.com/vids/intro_00/v01/master.m3u8',
'https://pp.tedcdn.com/vids/intro_01/v01/master.m3u8',
'https://pp.tedcdn.com/vids/intro_02/v01/master.m3u8',
'https://pp.tedcdn.com/vids/intro_03/v01/master.m3u8',
'https://pp.tedcdn.com/vids/intro_04/v01/master.m3u8',
],
good: [
'https://hls.ted.com/talks/1377.m3u8',
'https://hls.ted.com/talks/93.m3u8',
'https://hls.ted.com/talks/1042.m3u8',
'https://hls.ted.com/talks/1042.m3u8',
'https://hls.ted.com/talks/66.m3u8',
],
};
const initalVideoList = 'bad';
const maxVideoListIndex = 0;
let i = 0;
class VideoBugDemo extends Component {
constructor(){
super();
this.state = {
show:true,
currentVideoListName: initalVideoList,
videoUri: videos[initalVideoList][i],
paused: false,
};
}
pausePlay = () => {
this.setState({
paused: !this.state.paused,
});
};
toggle = () => {
this.setState({
currentVideoListName: this.state.currentVideoListName === 'bad' ? 'good' : 'bad',
},this.setNextVideo);
};
setNextVideo = () => {
i++;
if(i > maxVideoListIndex || !videos[this.state.currentVideoListName][i]){
i = 0;
}
this.setState({
videoUri: videos[this.state.currentVideoListName][i],
show: false,
}, () => {
setTimeout(() => {
this.setState({
show: true,
});
},1000);
});
};
render() {
if (!this.state.show){
return (
<View style={{
width:300,
aspectRatio: 16/9,
backgroundColor:'red',
}}
/>
);
}
return (
<View>
<Video
source={{uri:this.state.videoUri}}
paused={this.state.paused}
style={{
width:300,
aspectRatio: 16/9
}}
// muted
/>
<TouchableOpacity onPress={this.setNextVideo} style={{borderWidth:2,margin:10}}>
<Text>Next video</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.toggle} style={{borderWidth:2,margin:10}}>
<Text>Swap video list (currently set to {this.state.currentVideoListName})</Text>
</TouchableOpacity>
<TouchableOpacity onPress={this.pausePlay} style={{borderWidth:2,margin:10}}>
<Text>{this.state.paused ? 'play (currently paused)' : 'pause (currently playing)'})</Text>
</TouchableOpacity>
</View>
);
}
}
export default VideoBugDemo;
Hello
There are many streams with this problem.
You can fix easily that for non-HLS streams with a small modification of the react-native-video source code.
In this file:
brentvatne/exoplayer/ReactExoplayerView.java
you can edit this method:
private MediaSource buildMediaSource(Uri uri, String overrideExtension) {
.....
case C.TYPE_OTHER:
DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
extractorsFactory.setTsExtractorFlags(DefaultTsPayloadReaderFactory.FLAG_ALLOW_NON_IDR_KEYFRAMES);
return new ExtractorMediaSource(uri, mediaDataSourceFactory, extractorsFactory, mainHandler, null);
This is very common problem with exo player and the developers should include
prop for ALLOW_NON_IDR_KEYFRAMES to overcome this.
Many streams have iFrames which are not IDR and often exoplayer doesn't plays them.
But I don't know how to pass DefaultExtractorsFactory() to HlsMediaSource to
make the player work and for HLS streams, because if the HLS stream consists MPEG-TS,
we should set somehow ALLOW_NON_IDR_KEYFRAMES and for it
If the developers decide to work for solution I can also give here for several days 2-3 streams. One correct, one which is not playable without this option ALLOW_NON_IDR_KEYFRAMES etc.
"defualt" - you can analyze streams with ffprobe
best regards
On android I have a component/screen where i have imported the react-native-video component to play videos which works prefect. But after going back and forth(the component gets mounted/unmounted) to that screen and playing other videos it wont play anymore it just gets stuck on buffering(the function passed as buffering props is called only once with isBuffering true and onLoad is never triggered) no matter what video i try to play, I need to kill the app and run it again after which it works but if I repeat the mentioned steps it happens again.
@bajaga Did you ever find a solution to your problem?
I discovered another problem with react-native-video.
Big problem with many devices. ExoPlayer / MediaPlayer plays low resolution
standard definition files/streams mpeg-ts with awful quality.
For example it's easy to see the problem in channels with rounded logos.
The logo, texts are "aliased" with bad pixelisation. I checked it on amlogic devices, Smart TV-s etc.
The result is same. I checked with .ts file which captured from multicast stream.
The same file plays perfectly in the default android video player,
but with poor quality in react-native-video (ExoPlayer,MediaPlayer).
I thought, that this is a hardware problem but I was wrong.
With react-native-video android with media player the problem is with the View which it uses.
This is buggy:
https://github.com/yqritc/Android-ScalableVideoView
Modification the source of brentvante/react for MediaPlayer to use standard VideoView solves the problem, but I don't know how to solve it with ExoPlayer
Brentvante should edit his code to not use ScllableVideoView, but standard VideoView insted.
The difference is huge
Hi, (sorry for my English).
I think this issue is related to playWhenReady, because in adb logcat when the video freezes playWhenReady=false but should be true, so i added player.setPlayWhenReady(true); to private void videoLoaded() before eventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height,
getAudioTrackInfo(), getTextTrackInfo(), getVideoTrackInfo()); https://github.com/react-native-community/react-native-video/blob/c30f246f5694452f4f081ff30ac4523dfd89f41d/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java#L633
This change causes the video played after load but in my case this is not problem.
After 2 days i did not see any video freeze and i think this solved my problem.
Edit:
My problem was related to requestAudioFocus().
Could be a PR created from @hoorsa solution? It fixed one issue we had with HLS when switching between channels.
After changing channels (and sending the url to the exoplayer) 50 times (always 50....) the stream was freezing.
Thx for your solution @hoorsa
Hi, (sorry for my English).
I think this issue is related toplayWhenReady, because inadb logcatwhen the video freezesplayWhenReady=falsebut should betrue, so i addedplayer.setPlayWhenReady(true);toprivate void videoLoaded()beforeeventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height, getAudioTrackInfo(), getTextTrackInfo(), getVideoTrackInfo());This change causes the video played after load but in my case this is not problem.
After 2 days i did not see any video freeze and i think this solved my problem.Edit:
My problem was related torequestAudioFocus().
Thank you ! This solved our freezing video issue
Hi, (sorry for my English).
I think this issue is related toplayWhenReady, because inadb logcatwhen the video freezesplayWhenReady=falsebut should betrue, so i addedplayer.setPlayWhenReady(true);toprivate void videoLoaded()beforeeventEmitter.load(player.getDuration(), player.getCurrentPosition(), width, height, getAudioTrackInfo(), getTextTrackInfo(), getVideoTrackInfo());This change causes the video played after load but in my case this is not problem.
After 2 days i did not see any video freeze and i think this solved my problem.Edit:
My problem was related torequestAudioFocus().
HII @hoorsa I'm having same problem, How you resolved it ?
My video lags a frame then plays smooth if i use video which has audio,
but if i used the video which does not have audio then it does not lag. can you help me with that?
I'm using [email protected]
react-native 0.55.4
Hello
There are many streams with this problem.
You can fix easily that for non-HLS streams with a small modification of the react-native-video source code.
In this file:
brentvatne/exoplayer/ReactExoplayerView.java
you can edit this method:private MediaSource buildMediaSource(Uri uri, String overrideExtension) { ..... case C.TYPE_OTHER: DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory(); extractorsFactory.setTsExtractorFlags(DefaultTsPayloadReaderFactory.FLAG_ALLOW_NON_IDR_KEYFRAMES); return new ExtractorMediaSource(uri, mediaDataSourceFactory, extractorsFactory, mainHandler, null);This is very common problem with exo player and the developers should include
prop for ALLOW_NON_IDR_KEYFRAMES to overcome this.
Many streams have iFrames which are not IDR and often exoplayer doesn't plays them.But I don't know how to pass DefaultExtractorsFactory() to HlsMediaSource to
make the player work and for HLS streams, because if the HLS stream consists MPEG-TS,
we should set somehow ALLOW_NON_IDR_KEYFRAMES and for itIf the developers decide to work for solution I can also give here for several days 2-3 streams. One correct, one which is not playable without this option ALLOW_NON_IDR_KEYFRAMES etc.
"defualt" - you can analyze streams with ffprobe
best regards
Hello, actually, this solution breeds reference errors for DefaultTsPayloadReaderFactory, and it is not clear how to import this, as even trying to import it as extractor class, the build fails. So, I would highly appreciate the working code solution here, or an example of the flag passed down as a prop to Video, IF the PR discussed about did come to fruition. Thank you for any input.
Is there a good solution to the same problem @defualt @ervishu83 @cobarx @GrinchakAndrew @bajaga
Most helpful comment
On android I have a component/screen where i have imported the react-native-video component to play videos which works prefect. But after going back and forth(the component gets mounted/unmounted) to that screen and playing other videos it wont play anymore it just gets stuck on buffering(the function passed as buffering props is called only once with isBuffering true and onLoad is never triggered) no matter what video i try to play, I need to kill the app and run it again after which it works but if I repeat the mentioned steps it happens again.