Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Several Video instance in memory not working on Android #2984

Closed
douzal34 opened this issue Jan 4, 2023 · 18 comments
Closed

Several Video instance in memory not working on Android #2984

douzal34 opened this issue Jan 4, 2023 · 18 comments

Comments

@douzal34
Copy link

douzal34 commented Jan 4, 2023

Bug

Happy new year to all !

I am the creator of SoSkills app which is available on Apple and Android
SoSkills is a video sharing community application in the gaming ecosystem.
More info here https://soskills.io

Keep in mind user can swipe through videos on the Home page with FlatList as Instagram short, TikTok etc

If user want to see these videos on his profile, he changed screen without umounting Home page and he goes on Profile page.
Then he clicks on these videos and he starts see videos. At this point, i will generate a new FlatList in memory with Video component player too.
When this case happen, react-native-video will not work on new Video component cause too many instances of Video is already up.
This bug occur exclusively on Android not on Apple.

So the trick is to hide Video component from Home page in order to allocate memory and instance to Video component on Profile page, otherwise Video component is not loading the video and user is stuck.
It's a shame to do that, cause it's impact user experience.

Platform

  • Android with Redmi Note 10S phone
  • IOS with Iphone 12 pro

Environment info

Screenshot 2023-01-04 at 15 42 58

React native info output:

React native: 0.67.3
React native-video version: [v6.0.0-alpha.4]

Steps To Reproduce

Create a FlatList with videos, go on other page and let the Home page still active, start a new FlatList with Video component, video will not load the video, user will be stuck

Expected behaviour

I want to be able to have some Video component already mounted on paused and to have some active Video component on other screen

Reproducible sample code

SoSkills is a private company, code is not open source so can't do that but i shared screenshot and video

Video sample

@douzal34 douzal34 changed the title Several Video Instance in memory not working on Android Several Video instance in memory not working on Android Jan 4, 2023
@iasreact1
Copy link

@douzal34 faces similar problem As there is so many videos within the flatlist multiple videos plays simultaneously and most of the time the app stuck and Andorid not responding message showing ..what to do for that ? please help ....

@douzal34
Copy link
Author

douzal34 commented Jan 10, 2023

I just allowing video component to be active for three videos in the flat List, the current index, the top and the bottom.
By doing this, you have just three allocated video player, but if you want more, some of my users have issue, so i let this configuration. In Apple no restriction so user experience is clearly better.
It also depend the phone user have, for example a phone at 150 dollar meet this issue more often than other cause less memory available.
@iasreact1

@iasreact1
Copy link

I want to active the video component active for the current index of the flatlist after (as flatlist contain images and videos) that when imgae component coming it will deactive the video component or video instance , only video instance active when current index is a video file ....but please help how to deactive/active video instance Please help sir @douzal34

@fsher
Copy link

fsher commented Feb 13, 2023

I think we might've faced a similar issue (react-native-video@6.0.0-alpha.4, but we've tried the latest 5.x.x as well).

We have a FlatList with multiple relatively small videos (512x512 or less) running simultaneously (up to 50) and looped. Videos are fetched from a remote source. Works perfectly fine on iOS, however after some time the app gets frozen on Android. Specifically, android 13.

We've tested this on multiple devices, on android 11, 12 and 13. We've noticed that after 1-4 minutes (depending on the phone and the amount of videos running) the whole app becomes unresponsive. For android 12 and lower - fine and dandy.

We ran a profiler and haven't noticed a memory leak there (memory increases, but gc was doing it's job), but worth double checking.

But (gonna repeat myself) this issue happens for us specifically on android 13. Please correct me if this is unrelated.

Would love to see a response from the maintainers, thank you in advance!

P.S. we've noticed an unrelated thing as well: if the video is looped, by the end of every iteration the video would get refetched. react-native-video-cache package improves the situation by acting as a proxy, however I would've expected that if the video is looped there is no need to refetch it every time. Again, likely to be unrelated.

P.P.S we haven't tried another package (e.g. expo-av), but based on their implementation they also use the ExoPlayer package (as well as the native MediaPlayer, but I'm not 100% how do they decide which one to use yet). So it's hard for me to say if it's the exoplayer problem, an android 13 problem or react-native-video problem.

React Native: 0.69.2
React Native Video: 6.0.0-alpha.4 / -alpha.5

@fsher
Copy link

fsher commented Feb 14, 2023

UPD: after trying to reproduce this on a clean project, I can say that the issue I described above is not related to react-native-video.

No lags or freezes on a completely new project ran on android 13. Tested both on react-native@0.69.2 and 0.71.1. So it seems that there might be some package that conflicts or leaks specifically on android 13, however it doesn't seem to be react-native-video.

@douzal34 highly recommend testing on a fresh project. Since videos are quite memory-consuming part of RN, highly suggest checking other packages that are used directly or indirectly. (like reanimated for instance).

@fsher
Copy link

fsher commented Feb 15, 2023

Might be related, started noticing similar logs in Android Studio: #2767

@fsher
Copy link

fsher commented Feb 22, 2023

FYI, after many more days of debugging, my issue it turned out to be linked to this: facebook/react-native#34583. Specific to Android 13 and inverted Flatlist.

@douzal34
Copy link
Author

douzal34 commented Feb 22, 2023

Hi @fsher !

First, thanks for your effort in order to find a solution.
I'm also using react-native-video-cache in order to have content in cache and not having to refetch content every time.

I am not using inverted on FlatList and i doubt the issue come from this.
I really think it's an issue about memory used by rnv and for now i haven't solution on this case.

I saw #2723 and i'm not surprised about theirs issues. For my case largeHeap and hardwareAccelerated was already setup, it help on some cases but not for all cases.

I mean, i have some users who have a very light Android phone like 130-150 euros and when there's some issues memory they are first to have issues cause they don't have a lot of memory available to handle these cases.

For my pro phone 300 euros, issue appear rarely, unmount / mount some video component with screenIsFocused hook is the trick in order to let users see videos. the bad way of this is you can't preload many videos, so in some cases they have to wait in order to see videos.
On Apple, it's not the cases, you can preload 5 videos which are not currentIndex on FlatList and having other rnv on profile page but in Android, you can't do that.

I hope we will find a solution !

@MartianH
Copy link

MartianH commented Mar 25, 2023

Greetings,

I stumbled upon this ticket (coming from ticket #2723) as I have the same problems on Android ("react-native-video": "^6.0.0-alpha.5"). Having multiple instances would make my application cash, while this would not be the case on android. After a bit of digging in my logcat and finding these logs:

W ExoPlayer Warning: Free memory reached 0, forcing garbage collection
W ExoPlayer Warning: Free memory reached 0, forcing garbage collection

I followed a recommendation (#2767 (comment)) to limit the buffer to solve a known exoplayer problem described here.

So I set bufferConfig to the following:

   {
          minBufferMs: 2500,
          maxBufferMs: 5000, // default is 50 000, 50 seconds
          bufferForPlaybackMs: 2500,
          bufferForPlaybackAfterRebufferMs: 2500,
    }

The videos I use as an example are not longer than a minute as such I do not want to buffer 50 seconds on repeat.

My Video component:

import { useIsFocused } from '@react-navigation/native';
import Video from 'react-native-video';
import convertToProxyURL from 'react-native-video-cache';

// [omitted]

  <Video
        repeat
        disableFocus
        useTextureView={false}
        paused={!isVisible || !isFocused}
        muted={isFocused ? isMuted : true}
        source={{ uri: convertToProxyURL(media.uri) }} // Can be a URL or a local file.
        style={styles.video}
        resizeMode={'cover'}
        bufferConfig={{
          minBufferMs: 2500,
          maxBufferMs: 5000,
          bufferForPlaybackMs: 2500,
          bufferForPlaybackAfterRebufferMs: 2500,
        }}
  />

This has stopped the application from crashing.

Edit: I still get blank screens instead of videos when I push too many pages on the Navigation stack ("@react-navigation/native-stack": "^6.9.9",). Here are the logs from logcat:

03-25 14:24:44.596  7778  7778 I ExoPlayerImpl: Init 2920611 [ExoPlayerLib/2.18.1] [cheetah, Pixel 7 Pro, Google, 33]
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.AsynchronousMediaCodecAdapter.initialize(AsynchronousMediaCodecAdapter.java:160)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.AsynchronousMediaCodecAdapter.access$100(AsynchronousMediaCodecAdapter.java:50)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.AsynchronousMediaCodecAdapter$Factory.createAdapter(AsynchronousMediaCodecAdapter.java:103)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.DefaultMediaCodecAdapterFactory.createAdapter(DefaultMediaCodecAdapterFactory.java:108)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.initCodec(MediaCodecRenderer.java:1108)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1019)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodecOrBypass(MediaCodecRenderer.java:546)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.onInputFormatChanged(MediaCodecRenderer.java:1450)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.onInputFormatChanged(MediaCodecVideoRenderer.java:877)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.readSourceOmittingSampleData(MediaCodecRenderer.java:963)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:779)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:989)
03-25 14:24:44.761  7778 14493 W MediaCodecRenderer:       at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:490)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:   com.google.android.exoplayer2.mediacodec.MediaCodecRenderer$DecoderInitializationException: Decoder init failed: c2.exynos.h264.decoder, Format(1, null, null, video/avc, avc1.64002A, -1, null, [1080, 2048, 25.0], [-1, -1])
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1030)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodecOrBypass(MediaCodecRenderer.java:546)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.onInputFormatChanged(MediaCodecRenderer.java:1450)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.onInputFormatChanged(MediaCodecVideoRenderer.java:877)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.readSourceOmittingSampleData(MediaCodecRenderer.java:963)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:779)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:989)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:490)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.AsynchronousMediaCodecAdapter.initialize(AsynchronousMediaCodecAdapter.java:160)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.AsynchronousMediaCodecAdapter.access$100(AsynchronousMediaCodecAdapter.java:50)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.AsynchronousMediaCodecAdapter$Factory.createAdapter(AsynchronousMediaCodecAdapter.java:103)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.DefaultMediaCodecAdapterFactory.createAdapter(DefaultMediaCodecAdapterFactory.java:108)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.initCodec(MediaCodecRenderer.java:1108)
03-25 14:24:44.762  7778 14493 E MediaCodecVideoRenderer:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1019)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal: Playback error
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:   com.google.android.exoplayer2.ExoPlaybackException: MediaCodecVideoRenderer error, index=0, format=Format(1, null, null, video/avc, avc1.64002A, -1, null, [1080, 2048, 25.0], [-1, -1]), format_supported=YES
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:566)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at android.os.Handler.dispatchMessage(Handler.java:102)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at android.os.Looper.loopOnce(Looper.java:201)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at android.os.Looper.loop(Looper.java:288)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at android.os.HandlerThread.run(HandlerThread.java:67)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:   Caused by: com.google.android.exoplayer2.mediacodec.MediaCodecRenderer$DecoderInitializationException: Decoder init failed: c2.exynos.h264.decoder, Format(1, null, null, video/avc, avc1.64002A, -1, null, [1080, 2048, 25.0], [-1, -1])
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1030)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodecOrBypass(MediaCodecRenderer.java:546)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.onInputFormatChanged(MediaCodecRenderer.java:1450)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.video.MediaCodecVideoRenderer.onInputFormatChanged(MediaCodecVideoRenderer.java:877)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.readSourceOmittingSampleData(MediaCodecRenderer.java:963)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.render(MediaCodecRenderer.java:779)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.ExoPlayerImplInternal.doSomeWork(ExoPlayerImplInternal.java:989)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.ExoPlayerImplInternal.handleMessage(ExoPlayerImplInternal.java:490)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       ... 4 more
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:   Caused by: android.media.MediaCodec$CodecException: start failed
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at android.media.MediaCodec.native_start(Native Method)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at android.media.MediaCodec.start(MediaCodec.java:2323)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.AsynchronousMediaCodecAdapter.initialize(AsynchronousMediaCodecAdapter.java:160)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.AsynchronousMediaCodecAdapter.access$100(AsynchronousMediaCodecAdapter.java:50)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.AsynchronousMediaCodecAdapter$Factory.createAdapter(AsynchronousMediaCodecAdapter.java:103)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.DefaultMediaCodecAdapterFactory.createAdapter(DefaultMediaCodecAdapterFactory.java:108)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.initCodec(MediaCodecRenderer.java:1108)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       at com.google.android.exoplayer2.mediacodec.MediaCodecRenderer.maybeInitCodecWithFallback(MediaCodecRenderer.java:1019)
03-25 14:24:44.763  7778 14493 E ExoPlayerImplInternal:       ... 11 more
03-25 14:24:45.162  7778 12628 W ExoPlayer Warning: Free memory reached 0, forcing garbage collection

Edit 2: Setting source to null seems to fix the issue.

As written in the docummentation for source (

Providing a null source value after loading a previous source will stop playback, and clear out the previous source content.

So I used a work around like so:

    <Video
       // ...
        source={isFocused ? { uri: convertToProxyURL(media.uri) } : null}
        // ...
    />

So now every time a screen gets out of focus, the source is set to null. No more memory problems and multiple instances play on the given screen. This might need work in terms of implementation, though. Especially because this is strictly an android issue.

Edit3: Setting source to null is of course a hacky work around. A system of using a placeholder component if it is not in focus (react-navigation) or not visible seems to be the better solution. This however means that next to the video, you need to keep a thumbnail of the first frame.

@wolfxpertlab
Copy link

wolfxpertlab commented Sep 30, 2023

please tell me how can I solved this android has not play video

my package.json
"react-native-video": "^6.0.0-alpha.8",
"react-native-video-cache": "^2.7.3",

and this is my

<Video
resizeMode='cover'
paused={index == viewableIndex ? pause : true}
style={styles.videoView}
automaticallyWaitsToMinimizeStalling={false}
source={index == viewableIndex ? { uri: convertToProxyURL(item.video) } : 0}
hideShutterView={true}
bufferConfig={{
minBufferMs: 2500,
maxBufferMs: 3000, // default is 50 000, 50 seconds
bufferForPlaybackMs: 2500,
bufferForPlaybackAfterRebufferMs: 2500,
}}
useTextureView={true}
progressUpdateInterval={250}
onError={handleError}
onLoadStart={handleLoadStart}
onLoad={handleLoad}
onReadyForDisplay={() => setVideoLoad(false)}
repeat
/>

                this is my react-native-config.js 
                 dependencies: {
    "react-native-video": {
        platforms: {
            android: {
                sourceDir: '../node_modules/react-native-video/android',
            },
        },
    },
},

also set setting.gradle set android player how can I solved it

please help me android not play smoothly and also show invalid url when set url is blank

@freeboub
Copy link
Collaborator

@wolfxpertlab you should stop the video, not only pause it.
If you just pause you will have too much video decoder instantiated which will cause issues

@wolfxpertlab
Copy link

@freeboub please explain with example , help me I am very stuck

how can I solved it play video smoothly in android and which solution use for other method stop video or decoder

@vargajacint
Copy link

which solution use for other method stop video or decoder

As I know, if u change source to null it will stop not just pause

@wolfxpertlab
Copy link

wolfxpertlab commented Oct 2, 2023

Thank You @vargajacint

when change to 0 to null that show error invalid url
any solution for how to play video smooth in android , any information to tell me

@wolfxpertlab
Copy link

wolfxpertlab commented Oct 2, 2023

Any idea for azure server service for play video in smoothly play in android and solved it

how can I encode and hls method for play video smoothly any information please tell me

encode or HLS , insort how can I implement and play smoothly

@freeboub
Copy link
Collaborator

Can you try following patch: #3416
It should improve behavior in case of decoder issue

@alexhernandez
Copy link

alexhernandez commented Dec 13, 2023

I have a FlatList w/ Videos and I was able to workaround this Memory issue by disabling repeat on Android:

<Video
        ref={vidRef}
        // RNV SOURCE IS HLS | .m3u8
        source={uri}
        ...
        
        // RNV ANDROID ISSUE - `hideShutterView` ONLY WORKS W/ TEXTURE VIEWS NOT SURFACE VIEWS :/
        useTextureView
        hideShutterView
        
        // RNV VIDEO LOOP (REPEAT) CAUSES MEMORY CRASH
        repeat={Platform.OS === 'android' ? false : true}
      />

Not the best fix since I need this feature, but seems to work 🤷

@freeboub
Copy link
Collaborator

To be retested on beta.6

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

8 participants