TheWidlarzGroup / react-native-video

A <Video /> component for react-native
https://docs.thewidlarzgroup.com/react-native-video/
MIT License
7.2k stars 2.9k forks source link

Add caching #99

Closed jamesfzhang closed 2 years ago

jamesfzhang commented 9 years ago

How do you cache a video that's downloaded over the network?

DavitVosk commented 6 years ago

Has anyone solved this problem?

hkdahal commented 6 years ago

@DavitVosk I am not sure how others have solved it (looks like my way is similar to @rnowm), but the way I solved it on my project is I started writing my own downloader based off of this project: https://github.com/kfiroo/react-native-cached-image. Once you make that downloader work, you could load the local file path as your source uri.

Something like:

const mediaUrl = MEDIA.cached ? `file://${MEDIA.path}` : MEDIA.url
<Video source={ uri: mediaUrl } />
DavitVosk commented 6 years ago

@hkdahal thanks for your answer. Can you please share your created downloader file that we can use it? Thanks

DavitVosk commented 6 years ago

@hkdahal Also can you please explain how that work? You use https://github.com/kfiroo/react-native-cached-image package with https://github.com/kfiroo/react-native-cached-image/commit/31ad016afabcbe42e3c1eb058a0d9a57b0fb615f PR, but how react-native-video sees that the videos are cached? How they interact with each other?

BunHouth commented 6 years ago

@n1ru4l I got error as image bellow.

screen shot 2018-07-05 at 5 23 57 pm 1
hkdahal commented 6 years ago

@DavitVosk I will create a gist or share a separate project that does the interaction between these packages later this weekend. I will mention you over there.

n1ru4l commented 6 years ago

@BunHouth @DavitVosk Sorry for the late answer. Did you all setup the package like described in the Pull Request? Lets continue there and stop spamming this issue 😅https://github.com/react-native-community/react-native-video/pull/955

roycclu commented 6 years ago

@n1ru4l It's not spamming if people are trying your package and responding with roadblocks it's very healthy discussion. I see you added SPTPersistentCache in your podspec as dependency. Any idea why the header isn't found?

n1ru4l commented 6 years ago

@roycclu It is better to discuss possible problems related to the pull request in the comments of the pull request..

n1ru4l commented 6 years ago

@roycclu @BunHouth @DavitVosk I updated my pull request (#955). Please check out the private fork n1ru4l/react-native-video@3.1.0-alpha.2 or the example app, located under (examples/video-caching) (if you do not know how to setup your project with cocoapods.

The issues you guys mentioned should be fixed by now.

Would love to hear your feedback (in the discussion of #955)!

cobarx commented 6 years ago

Thanks for making these changes @n1ru4l! I will add feedback on the PR.

This is a pretty impactful change and as @n1ru4l has mentioned, we need testing and feedback to make sure this is ready to go. If you want to use this feature, please start testing it and letting us know how well it works. Once I have a couple thumbs up, I will do a review and get it merged.

darekg11 commented 6 years ago

As caching is not yet availalbe out of the box for react-native-video on both Android and IOS, we have been using: https://github.com/joltup/rn-fetch-blob to download our videos from S3, (it supports progress callback so you can add progress-bars etc), save it to a device storage and point react-native-video to URI like so:

    rfblob.config({
        fileCache: true,
        path: filePath // where you want to save a file
      }).fetch('GET', 'your-hosting-url/file.mp4')
        .then(result => {
           const filePath = result.path();
           const sourceForVideoPlayer = {
               uri: 'file://' + filePath
           }
        })
    }

And when Video Player component is mounted, we check if there is already a file on device storage with matching name and if so, we just load video from storage instead of downloading it once more. Of course, you also need to clean your cache directory by yourself but this is a small trade off for solution that works on both IOS and Android. Maybe it will help someone else, as soon as caching is supported on both platforms, we will be happy to switch

webbin commented 5 years ago

As caching is not yet availalbe out of the box for react-native-video on both Android and IOS, we have been using: https://github.com/joltup/rn-fetch-blob to download our videos from S3, (it supports progress callback so you can add progress-bars etc), save it to a device storage and point react-native-video to URI like so:

    rfblob.config({
        fileCache: true,
        path: filePath // where you want to save a file
      }).fetch('GET', 'your-hosting-url/file.mp4')
        .then(result => {
           const filePath = result.path();
           const sourceForVideoPlayer = {
               uri: 'file://' + filePath
           }
        })
    }

And when Video Player component is mounted, we check if there is already a file on device storage with matching name and if so, we just load video from storage instead of downloading it once more. Of course, you also need to clean your cache directory by yourself but this is a small trade off for solution that works on both IOS and Android. Maybe it will help someone else, as soon as caching is supported on both platforms, we will be happy to switch

hello, is there any way to download the video with rn-fetch-blob, and play the video while downloading?It's so long for waiting the downloading task complete.

n1ru4l commented 5 years ago

@webbin No, there is not.

For android video caching I am currently using this: https://github.com/n1ru4l/react-native-video/commit/0e1c7c273e2793392580bda2c1f9926092547546 (uses a HTTP proxy to cache the file).

The idea came from this article: https://instagram-engineering.com/improving-video-playback-on-android-2f6c6a0058d

I use this is my private fork and hope I will have the time to someday do a proper implementation for react-native-video.

gazedash commented 5 years ago

@webbin No, there is not.

For android video caching I am currently using this: n1ru4l@0e1c7c2 (uses a HTTP proxy to cache the file).

The idea came from this article: https://instagram-engineering.com/improving-video-playback-on-android-2f6c6a0058d

I use this is my private fork and hope I will have the time to someday do a proper implementation for react-native-video.

What's the progress on this?

n1ru4l commented 5 years ago

@gazedash I am still using it with patch-package on react-native-video@4.3.1. Had no time to clean it up and release it as part of react-native-video.

patches/react-native-video+4.3.1.patch

patch-package
--- a/node_modules/react-native-video/android-exoplayer/build.gradle
+++ b/node_modules/react-native-video/android-exoplayer/build.gradle
@@ -31,5 +31,5 @@ dependencies {
         exclude group: 'com.squareup.okhttp3', module: 'okhttp'
     }
     implementation 'com.squareup.okhttp3:okhttp:3.12.1'
-
+    implementation 'com.danikula:videocache:2.7.1'
 }
--- a/node_modules/react-native-video/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java
+++ b/node_modules/react-native-video/android-exoplayer/src/main/java/com/brentvatne/exoplayer/DataSourceUtil.java
@@ -2,6 +2,7 @@ package com.brentvatne.exoplayer;

 import android.content.Context;
 import android.content.ContextWrapper;
+import android.net.Uri;

 import com.facebook.react.bridge.ReactContext;
 import com.facebook.react.modules.network.CookieJarContainer;
@@ -17,6 +18,7 @@ import com.google.android.exoplayer2.util.Util;
 import okhttp3.Cookie;
 import okhttp3.JavaNetCookieJar;
 import okhttp3.OkHttpClient;
+import com.danikula.videocache.HttpProxyCacheServer;
 import java.util.Map;

@@ -27,6 +29,7 @@ public class DataSourceUtil {

     private static DataSource.Factory rawDataSourceFactory = null;
     private static DataSource.Factory defaultDataSourceFactory = null;
+    private static HttpProxyCacheServer proxy = null;
     private static String userAgent = null;

     public static void setUserAgent(String userAgent) {
@@ -84,4 +87,14 @@ public class DataSourceUtil {

         return okHttpDataSourceFactory;
     }
+
+    public static Uri getCacheUri(Uri uri, Context context) {
+        if (proxy == null) {
+            proxy = new HttpProxyCacheServer.Builder(context)
+                .maxCacheSize(1024 * 1024 * 512)
+                .maxCacheFilesCount(20)
+                .build();
+        }
+        return Uri.parse(proxy.getProxyUrl(uri.toString()));
+    }
 }
--- a/node_modules/react-native-video/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
+++ b/node_modules/react-native-video/android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java
@@ -366,13 +366,7 @@ class ReactExoplayerView extends FrameLayout implements
     }

     private boolean requestAudioFocus() {
-        if (disableFocus) {
-            return true;
-        }
-        int result = audioManager.requestAudioFocus(this,
-                AudioManager.STREAM_MUSIC,
-                AudioManager.AUDIOFOCUS_GAIN);
-        return result == AudioManager.AUDIOFOCUS_REQUEST_GRANTED;
+        return true;
     }

     private void setPlayWhenReady(boolean playWhenReady) {
@@ -759,7 +753,7 @@ class ReactExoplayerView extends FrameLayout implements
             boolean isOriginalSourceNull = srcUri == null;
             boolean isSourceEqual = uri.equals(srcUri);

-            this.srcUri = uri;
+            this.srcUri = DataSourceUtil.getCacheUri(uri, themedReactContext);
             this.extension = extension;
             this.requestHeaders = headers;
             this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, BANDWIDTH_METER, this.requestHeaders);
eddyjusufi commented 5 years ago

Have there been any plans for implementing the cache functionality in this library?

igor-lemon commented 5 years ago

Hi there! What about caching video files when a url ends like https://.../file.mp4?access_token=xxx ?

n1ru4l commented 5 years ago

@igor-lemon feel free to send a pull request that allows registering a cache key normalizer.

vargajacint commented 3 years ago

Any update?

antoinemaillard commented 3 years ago

@vargajacint We just created a fork to add basic caching feature to the <Video/> component (Android and ExoPlayer only, since caching is already native on iOS)

You can find it here: https://github.com/jowapp/react-native-video

(@n1ru4l if you think it's worth it, we can send a PR)

tl;dr: just reference our repo in your package.json react-native-video entry and add the useCache prop to your <Video/> component. For more details and advanced features, have a look at our updated README

[Note: We are Jow, a wonderful startup based in Paris, offering delighful recipes and helping do your grocery shopping according to what you like to eat. And we're also hiring talented people, especially back & front developers!)]

AndresTIY commented 3 years ago

Hi @antoinemaillard . Thanks for providing this repo!

Does this work for HLS?

If useCache prop is set, cache will be used for all non-streamed content (ie. except for Microsoft SmoothSteaming, DASH, HLS)

I see that it does support HLS but when I try to console log the cache stats with:

ExoPlayerCache.getCacheStats()
  .then(cacheStats => {
    console.log(cacheStats)
  })

It shows an empty object. Yet, with an mp4, I see all of the stats.

Also, does this handle deleting the cached video as well?

Thanks :)

eqlion commented 3 years ago

@antoinemaillard Thank you for your fork enabling caching on Android! Is there any way to imperatively cache video ahead of time in order to be able to play it instantly? (Something like Image.prefetch() in React Native or FastImage.preload() in React Native FastImage) Nevermind, I managed to achieve it by downloading the videos in advance with React Native FS and playing them from local source.

mirceaciu commented 3 years ago

Hi @antoinemaillard . Thanks for providing this repo!

Does this work for HLS?

looking at the code there is support for those types of media but for some reason the cache does not work

case C.TYPE_DASH:
    DataSource.Factory dataSourceFactory = buildDataSourceFactory(false);

    mediaSource = new DashMediaSource.Factory(
            new DefaultDashChunkSource.Factory(mediaDataSourceFactory),
            buildDataSourceFactory(false)
    ).setLoadErrorHandlingPolicy(
            config.buildLoadErrorHandlingPolicy(minLoadRetryCount)
    ).createMediaSource(uri);
    break;

given a url like https://fictive-api.com/dash/1766e4a8f33d49a497e9ff0fe59c130c.mp4/manifest.mpd it will detect that the type is DASH, play the video but won't cache :(

AdityaVernekar commented 11 months ago

Thank you for your fork enabling caching on Android! ~Is there any way to imperatively cache video ahead of time in order to be able to play it instantly? (Something like Image.prefetch() in React Native or FastImage.preload() in React Native FastImage)~ Nevermind, I managed to achieve it by downloading the videos in advance with React Native FS and playing them from local source.

Can you tell me how you did this ??