Skip to content

Commit 1f64231

Browse files
Merge pull request #3 from relivecc/exoplayer-cache-and-disable-focus-fix-headers
Exoplayer cache and disable focus fix headers
2 parents b0c0ac1 + 36a7172 commit 1f64231

20 files changed

Lines changed: 249 additions & 103 deletions

Video.js

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1-
import React, {Component} from 'react';
1+
import React, {
2+
Component
3+
} from 'react';
24
import PropTypes from 'prop-types';
3-
import {StyleSheet, requireNativeComponent, NativeModules, View, ViewPropTypes, Image, Platform} from 'react-native';
5+
import {
6+
StyleSheet,
7+
requireNativeComponent,
8+
NativeModules,
9+
View,
10+
ViewPropTypes,
11+
Image,
12+
Platform
13+
} from 'react-native';
414
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
515
import TextTrackType from './TextTrackType';
616
import VideoResizeMode from './VideoResizeMode.js';
@@ -11,7 +21,14 @@ const styles = StyleSheet.create({
1121
},
1222
});
1323

14-
export { TextTrackType };
24+
const {
25+
ExoPlayerCache
26+
} = NativeModules;
27+
28+
export {
29+
TextTrackType,
30+
ExoPlayerCache,
31+
};
1532

1633
export default class Video extends Component {
1734

@@ -26,17 +43,17 @@ export default class Video extends Component {
2643
setNativeProps(nativeProps) {
2744
this._root.setNativeProps(nativeProps);
2845
}
29-
46+
3047
toTypeString(x) {
3148
switch (typeof x) {
3249
case "object":
3350
return x instanceof Date
34-
? x.toISOString()
51+
? x.toISOString()
3552
: JSON.stringify(x); // object, null
3653
case "undefined":
3754
return "";
3855
default: // boolean, number, string
39-
return x.toString();
56+
return x.toString();
4057
}
4158
}
4259

@@ -59,16 +76,22 @@ export default class Video extends Component {
5976
}
6077
});
6178
} else {
62-
this.setNativeProps({ seek: time });
79+
this.setNativeProps({
80+
seek: time
81+
});
6382
}
6483
};
6584

6685
presentFullscreenPlayer = () => {
67-
this.setNativeProps({ fullscreen: true });
86+
this.setNativeProps({
87+
fullscreen: true
88+
});
6889
};
6990

7091
dismissFullscreenPlayer = () => {
71-
this.setNativeProps({ fullscreen: false });
92+
this.setNativeProps({
93+
fullscreen: false
94+
});
7295
};
7396

7497
_assignRoot = (component) => {
@@ -101,7 +124,9 @@ export default class Video extends Component {
101124

102125
_onSeek = (event) => {
103126
if (this.state.showPoster && !this.props.audioOnly) {
104-
this.setState({showPoster: false});
127+
this.setState({
128+
showPoster: false
129+
});
105130
}
106131

107132
if (this.props.onSeek) {
@@ -165,7 +190,9 @@ export default class Video extends Component {
165190

166191
_onPlaybackRateChange = (event) => {
167192
if (this.state.showPoster && event.nativeEvent.playbackRate !== 0 && !this.props.audioOnly) {
168-
this.setState({showPoster: false});
193+
this.setState({
194+
showPoster: false
195+
});
169196
}
170197

171198
if (this.props.onPlaybackRateChange) {

android-exoplayer/README.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,11 @@ https://github.com/google/ExoPlayer
1717
## ExoPlayer only props
1818

1919
```javascript
20-
2120
render() {
2221
return (
2322
<Video
2423
...
25-
disableFocus={true} // disables audio focus and wake lock (default false)
24+
disableFocus={true} // disables audio focus and wake lock (default true)
2625
onAudioBecomingNoisy={this.onAudioBecomingNoisy} // Callback when audio is becoming noisy - should pause video
2726
onAudioFocusChanged={this.onAudioFocusChanged} // Callback when audio focus has been lost - pause if focus has been lost
2827
/>
@@ -43,4 +42,3 @@ https://github.com/google/ExoPlayer
4342
## Unimplemented props
4443

4544
- Expansion file - `source={{ mainVer: 1, patchVer: 0 }}`
46-
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
package com.brentvatne.exoplayer;
2+
3+
import android.content.Context;
4+
import android.net.Uri;
5+
import android.util.Log;
6+
7+
import com.google.android.exoplayer2.upstream.cache.NoOpCacheEvictor;
8+
import com.google.android.exoplayer2.upstream.cache.Cache;
9+
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
10+
import com.google.android.exoplayer2.upstream.cache.CacheUtil;
11+
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
12+
import com.google.android.exoplayer2.upstream.DataSpec;
13+
import com.google.android.exoplayer2.upstream.DataSource;
14+
import com.google.android.exoplayer2.upstream.DataSourceInputStream;
15+
16+
import com.facebook.react.bridge.NativeModule;
17+
import com.facebook.react.bridge.Promise;
18+
import com.facebook.react.bridge.ReactApplicationContext;
19+
import com.facebook.react.bridge.ReactContext;
20+
import com.facebook.react.bridge.ReactContextBaseJavaModule;
21+
import com.facebook.react.bridge.ReactMethod;
22+
23+
import java.io.IOException;
24+
import java.io.File;
25+
import java.io.FileOutputStream;
26+
import java.io.OutputStream;
27+
28+
public class ExoPlayerCache extends ReactContextBaseJavaModule {
29+
30+
private static SimpleCache instance = null;
31+
32+
33+
public ExoPlayerCache(ReactApplicationContext reactContext) {
34+
super(reactContext);
35+
}
36+
37+
@Override
38+
public String getName() {
39+
return "ExoPlayerCache";
40+
}
41+
42+
@ReactMethod
43+
public void exportVideo(final String url, final Promise promise) {
44+
Log.d(getName(), "exportVideo");
45+
46+
Thread exportThread = new Thread(new Runnable() {
47+
@Override
48+
public void run() {
49+
Log.d(getName(), "Exporting...");
50+
Log.d(getName(), url);
51+
final Uri uri = Uri.parse(url);
52+
final DataSpec dataSpec = new DataSpec(uri, 0, 100 * 1024 * 1024, null); // TODO won't work for video's over 100 MB
53+
final SimpleCache downloadCache = ExoPlayerCache.getInstance(getReactApplicationContext());
54+
CacheUtil.CachingCounters counters = new CacheUtil.CachingCounters();
55+
56+
try {
57+
CacheUtil.getCached(
58+
dataSpec,
59+
downloadCache,
60+
counters
61+
);
62+
63+
// TODO check counters for when download is not complete // Download can complete during writing
64+
Log.d(getName(), "Cached " + counters.totalCachedBytes() + " bytes (start)");
65+
66+
DataSourceInputStream inputStream = new DataSourceInputStream(createDataSource(downloadCache), dataSpec);
67+
68+
File targetFile = new File(ExoPlayerCache.getCacheDir(getReactApplicationContext()) + "/" + uri.getLastPathSegment());
69+
OutputStream outStream = new FileOutputStream(targetFile);
70+
71+
byte[] buffer = new byte[8 * 1024];
72+
int bytesRead;
73+
try {
74+
while ((bytesRead = inputStream.read(buffer)) != -1) {
75+
outStream.write(buffer, 0, bytesRead);
76+
}
77+
} catch (IOException e) {
78+
// TODO this exception should not be thrown
79+
Log.d(getName(), "Read error");
80+
e.printStackTrace();
81+
}
82+
83+
CacheUtil.getCached(
84+
dataSpec,
85+
downloadCache,
86+
counters
87+
);
88+
89+
// TODO are we sure the complete video is downloaded?
90+
Log.d(getName(), "Cached " + counters.totalCachedBytes() + " bytes (end)");
91+
92+
Log.d(getName(), "Export succeeded");
93+
Log.d(getName(), targetFile.getPath());
94+
95+
promise.resolve(targetFile.getPath());
96+
} catch (Exception e) {
97+
Log.d(getName(), "Export error");
98+
e.printStackTrace();
99+
promise.reject(e);
100+
}
101+
}
102+
}, "export_thread");
103+
exportThread.start();
104+
}
105+
106+
public static SimpleCache getInstance(Context context) {
107+
if(instance == null) {
108+
instance = new SimpleCache(new File(ExoPlayerCache.getCacheDir(context)), new NoOpCacheEvictor());
109+
}
110+
return instance;
111+
}
112+
113+
private static String getCacheDir(Context context) {
114+
return context.getCacheDir().toString() + "/video";
115+
}
116+
117+
private DataSource createDataSource(Cache cache) {
118+
return new CacheDataSourceFactory(cache, DataSourceUtil.getDefaultDataSourceFactory(
119+
getReactApplicationContext(),
120+
null,
121+
null
122+
)).createDataSource();
123+
}
124+
125+
}

android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
import com.google.android.exoplayer2.Player;
3636
import com.google.android.exoplayer2.SimpleExoPlayer;
3737
import com.google.android.exoplayer2.Timeline;
38-
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
3938
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
4039
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
4140
import com.google.android.exoplayer2.metadata.Metadata;
@@ -60,7 +59,9 @@
6059
import com.google.android.exoplayer2.upstream.DataSource;
6160
import com.google.android.exoplayer2.upstream.DefaultAllocator;
6261
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
63-
import com.google.android.exoplayer2.util.MimeTypes;
62+
import com.google.android.exoplayer2.upstream.cache.Cache;
63+
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
64+
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
6465
import com.google.android.exoplayer2.util.Util;
6566

6667
import java.net.CookieHandler;
@@ -96,6 +97,7 @@ class ReactExoplayerView extends FrameLayout implements
9697
private Handler mainHandler;
9798
private ExoPlayerView exoPlayerView;
9899

100+
private SimpleCache downloadCache;
99101
private DataSource.Factory mediaDataSourceFactory;
100102
private SimpleExoPlayer player;
101103
private DefaultTrackSelector trackSelector;
@@ -125,7 +127,7 @@ class ReactExoplayerView extends FrameLayout implements
125127
private String textTrackType;
126128
private Dynamic textTrackValue;
127129
private ReadableArray textTracks;
128-
private boolean disableFocus;
130+
private boolean disableFocus = true;
129131
private float mProgressUpdateInterval = 250.0f;
130132
private boolean playInBackground = false;
131133
private boolean useTextureView = false;
@@ -179,6 +181,8 @@ public void setId(int id) {
179181
private void createViews() {
180182
clearResumePosition();
181183
mediaDataSourceFactory = buildDataSourceFactory(true);
184+
downloadCache = ExoPlayerCache.getInstance(getContext());
185+
182186
mainHandler = new Handler();
183187
if (CookieHandler.getDefault() != DEFAULT_COOKIE_MANAGER) {
184188
CookieHandler.setDefault(DEFAULT_COOKIE_MANAGER);
@@ -292,8 +296,8 @@ private MediaSource buildMediaSource(Uri uri, String overrideExtension) {
292296
case C.TYPE_HLS:
293297
return new HlsMediaSource(uri, mediaDataSourceFactory, mainHandler, null);
294298
case C.TYPE_OTHER:
295-
return new ExtractorMediaSource(uri, mediaDataSourceFactory, new DefaultExtractorsFactory(),
296-
mainHandler, null);
299+
return new ExtractorMediaSource.Factory(new CacheDataSourceFactory(downloadCache, mediaDataSourceFactory))
300+
.createMediaSource(uri);
297301
default: {
298302
throw new IllegalStateException("Unsupported type: " + type);
299303
}

android-exoplayer/src/main/java/com/brentvatne/react/ReactVideoPackage.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,26 @@
11
package com.brentvatne.react;
22

33
import com.brentvatne.exoplayer.ReactExoplayerViewManager;
4+
import com.brentvatne.exoplayer.ExoPlayerCache;
45
import com.facebook.react.ReactPackage;
56
import com.facebook.react.bridge.JavaScriptModule;
67
import com.facebook.react.bridge.NativeModule;
78
import com.facebook.react.bridge.ReactApplicationContext;
89
import com.facebook.react.uimanager.ViewManager;
910

11+
import java.util.ArrayList;
1012
import java.util.Collections;
1113
import java.util.List;
1214

1315
public class ReactVideoPackage implements ReactPackage {
1416

1517
@Override
1618
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
17-
return Collections.emptyList();
19+
List<NativeModule> modules = new ArrayList<>();
20+
21+
modules.add(new ExoPlayerCache(reactContext));
22+
23+
return modules;
1824
}
1925

2026
// Deprecated RN 0.47

examples/video-caching/ios/Podfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,5 @@ target 'VideoCaching' do
2828
'DevSupport'
2929
]
3030

31-
pod 'react-native-video/VideoCaching', :path => '../node_modules/react-native-video/react-native-video.podspec'
31+
pod 'react-native-video', :path => '../node_modules/react-native-video/react-native-video.podspec'
3232
end

examples/video-caching/ios/Podfile.lock

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@ PODS:
99
- glog (0.3.4)
1010
- React (0.56.0):
1111
- React/Core (= 0.56.0)
12-
- react-native-video/Video (3.1.0):
13-
- React
14-
- react-native-video/VideoCaching (3.1.0):
12+
- react-native-video (3.2.0):
1513
- DVAssetLoaderDelegate (~> 0.3.1)
1614
- React
17-
- react-native-video/Video
1815
- SPTPersistentCache (~> 1.1.0)
1916
- React/Core (0.56.0):
2017
- yoga (= 0.56.0.React)
@@ -73,7 +70,7 @@ DEPENDENCIES:
7370
- DoubleConversion (from `../node_modules/react-native/third-party-podspecs/DoubleConversion.podspec`)
7471
- Folly (from `../node_modules/react-native/third-party-podspecs/Folly.podspec`)
7572
- glog (from `../node_modules/react-native/third-party-podspecs/GLog.podspec`)
76-
- react-native-video/VideoCaching (from `../node_modules/react-native-video/react-native-video.podspec`)
73+
- react-native-video (from `../node_modules/react-native-video/react-native-video.podspec`)
7774
- React/Core (from `../node_modules/react-native`)
7875
- React/CxxBridge (from `../node_modules/react-native`)
7976
- React/DevSupport (from `../node_modules/react-native`)
@@ -119,10 +116,10 @@ SPEC CHECKSUMS:
119116
Folly: c89ac2d5c6ab169cd7397ef27485c44f35f742c7
120117
glog: b3b0330915eccea41c5cc9731a77cf564a9be5ea
121118
React: 1fe0eb13d90b625d94c3b117c274dcfd2e760e11
122-
react-native-video: 44c6befbc1526283ca1919891fcebe4680feade4
119+
react-native-video: 772ae2698c177bc0d5a0b0110e6ac71b2aa0d92d
123120
SPTPersistentCache: df36ea46762d7cf026502bbb86a8b79d0080dff4
124121
yoga: b1ce48b6cf950b98deae82838f5173ea7cf89e85
125122

126-
PODFILE CHECKSUM: f4123c35c77493d6ddbcb86898737abdf5e0fac8
123+
PODFILE CHECKSUM: a72d15643ecf681eee8bfdb9918eaa0cba0620f7
127124

128125
COCOAPODS: 1.5.3
Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,13 @@
55
#import "RCTVideoPlayerViewController.h"
66
#import "RCTVideoPlayerViewControllerDelegate.h"
77

8-
#if __has_include(<react-native-video/RCTVideoCache.h>)
9-
#import <react-native-video/RCTVideoCache.h>
10-
#import <DVAssetLoaderDelegate/DVURLAsset.h>
11-
#import <DVAssetLoaderDelegate/DVAssetLoaderDelegate.h>
12-
#endif
8+
#import "RCTVideoCache.h"
9+
#import "DVURLAsset.h"
10+
#import "DVAssetLoaderDelegate.h"
1311

1412
@class RCTEventDispatcher;
15-
#if __has_include(<react-native-video/RCTVideoCache.h>)
13+
1614
@interface RCTVideo : UIView <RCTVideoPlayerViewControllerDelegate, DVAssetLoaderDelegatesDelegate>
17-
#else
18-
@interface RCTVideo : UIView <RCTVideoPlayerViewControllerDelegate>
19-
#endif
2015

2116
@property (nonatomic, copy) RCTBubblingEventBlock onVideoLoadStart;
2217
@property (nonatomic, copy) RCTBubblingEventBlock onVideoLoad;

0 commit comments

Comments
 (0)