Merge remote-tracking branch 'upstream/master'
# Conflicts: # ios/RCTVideo.m # package.json
This commit is contained in:
		
							
								
								
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										11
									
								
								CHANGELOG.md
									
									
									
									
									
								
							@@ -1,5 +1,16 @@
 | 
			
		||||
## Changelog
 | 
			
		||||
 | 
			
		||||
### Version 3.0
 | 
			
		||||
* Inherit Android buildtools and SDK version from the root project [#1081](https://github.com/react-native-community/react-native-video/pull/1081)
 | 
			
		||||
* Automatically play on ExoPlayer when the paused prop is not set [#1083](https://github.com/react-native-community/react-native-video/pull/1083)
 | 
			
		||||
* Preserve Android MediaPlayer paused prop when backgrounding [#1082](https://github.com/react-native-community/react-native-video/pull/1082)
 | 
			
		||||
* Support specifying headers on ExoPlayer as part of the source [#805](https://github.com/react-native-community/react-native-video/pull/805)
 | 
			
		||||
* Prevent iOS onLoad event during seeking [#1088](https://github.com/react-native-community/react-native-video/pull/1088)
 | 
			
		||||
* ExoPlayer playableDuration incorrect [#1089](https://github.com/react-native-community/react-native-video/pull/1089)
 | 
			
		||||
 | 
			
		||||
### Version 2.3.1
 | 
			
		||||
* Revert PR to inherit Android SDK versions from root project. Re-add in 3.0 [#1080](https://github.com/react-native-community/react-native-video/pull/1080)
 | 
			
		||||
 | 
			
		||||
### Version 2.3.0
 | 
			
		||||
* Support allowsExternalPlayback on iOS [#1057](https://github.com/react-native-community/react-native-video/pull/1057)
 | 
			
		||||
* Inherit Android buildtools and SDK version from the root project [#999](https://github.com/react-native-community/react-native-video/pull/999)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										117
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										117
									
								
								README.md
									
									
									
									
									
								
							@@ -5,10 +5,14 @@ A `<Video>` component for react-native, as seen in
 | 
			
		||||
 | 
			
		||||
Requires react-native >= 0.40.0, for RN support of 0.19.0 - 0.39.0 please use a pre 1.0 version.
 | 
			
		||||
 | 
			
		||||
### Version 3.0 breaking changes
 | 
			
		||||
Version 3.0 features a number of changes to existing behavior. See [Updating](#updating) for changes.
 | 
			
		||||
 | 
			
		||||
## TOC
 | 
			
		||||
 | 
			
		||||
* [Installation](#installation)
 | 
			
		||||
* [Usage](#usage)
 | 
			
		||||
* [Updating](#updating)
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
 | 
			
		||||
@@ -51,7 +55,7 @@ Note: you can also use the `ignoreSilentSwitch` prop, shown below.
 | 
			
		||||
  
 | 
			
		||||
Run `react-native link` to link the react-native-video library.
 | 
			
		||||
 | 
			
		||||
`react-native link` don’t works properly with the tvOS target so we need to add the library manually.
 | 
			
		||||
`react-native link` doesn’t work properly with the tvOS target so we need to add the library manually.
 | 
			
		||||
 | 
			
		||||
First select your project in Xcode.
 | 
			
		||||
 | 
			
		||||
@@ -191,8 +195,6 @@ using System.Collections.Generic;
 | 
			
		||||
       onFullscreenPlayerDidPresent={this.fullScreenPlayerDidPresent}   // Callback after fullscreen started
 | 
			
		||||
       onFullscreenPlayerWillDismiss={this.fullScreenPlayerWillDismiss} // Callback before fullscreen stops
 | 
			
		||||
       onFullscreenPlayerDidDismiss={this.fullScreenPlayerDidDismiss}  // Callback after fullscreen stopped
 | 
			
		||||
       onProgress={this.setTime}               // Callback every ~250ms with currentTime
 | 
			
		||||
       onTimedMetadata={this.onTimedMetadata}  // Callback when the stream receive some metadata
 | 
			
		||||
       style={styles.backgroundVideo} />
 | 
			
		||||
 | 
			
		||||
// Later to trigger fullscreen
 | 
			
		||||
@@ -239,6 +241,8 @@ var styles = StyleSheet.create({
 | 
			
		||||
### Event props
 | 
			
		||||
* [onLoad](#onload)
 | 
			
		||||
* [onLoadStart](#onloadstart)
 | 
			
		||||
* [onProgress](#onprogress)
 | 
			
		||||
* [onTimedMetadata](#ontimedmetadata)
 | 
			
		||||
 | 
			
		||||
### Methods
 | 
			
		||||
* [seek](#seek)
 | 
			
		||||
@@ -492,9 +496,9 @@ Payload:
 | 
			
		||||
 | 
			
		||||
Property | Description
 | 
			
		||||
--- | ---
 | 
			
		||||
isNetwork | Boolean indicating if the media is being loaded from the network
 | 
			
		||||
type | Type of the media. Not available on Windows
 | 
			
		||||
uri | URI for the media source. Not available on Windows
 | 
			
		||||
isNetwork | boolean | Boolean indicating if the media is being loaded from the network
 | 
			
		||||
type | string | Type of the media. Not available on Windows
 | 
			
		||||
uri | string | URI for the media source. Not available on Windows
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
```
 | 
			
		||||
@@ -507,6 +511,46 @@ Example:
 | 
			
		||||
 | 
			
		||||
Platforms: all
 | 
			
		||||
 | 
			
		||||
#### onProgress
 | 
			
		||||
Callback function that is called every progressInterval seconds with info about which position the media is currently playing.
 | 
			
		||||
 | 
			
		||||
Property | Description
 | 
			
		||||
--- | ---
 | 
			
		||||
currentTime | number | Current position in seconds
 | 
			
		||||
playableDuration | number | Position to where the media can be played to using just the buffer in seconds
 | 
			
		||||
seekableDuration | number | Position to where the media can be seeked to in seconds. Typically, the total length of the media
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
```
 | 
			
		||||
{
 | 
			
		||||
  currentTime: 5.2,
 | 
			
		||||
  playableDuration: 34.6,
 | 
			
		||||
  seekableDuration: 888
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
#### onTimedMetadata
 | 
			
		||||
Callback function that is called when timed metadata becomes available
 | 
			
		||||
 | 
			
		||||
Payload:
 | 
			
		||||
 | 
			
		||||
Property | Type | Description
 | 
			
		||||
--- | --- | ---
 | 
			
		||||
metadata | array | Array of metadata objects
 | 
			
		||||
 | 
			
		||||
Example:
 | 
			
		||||
```
 | 
			
		||||
{
 | 
			
		||||
  metadata: [
 | 
			
		||||
    { value: 'Streaming Encoder', identifier: 'TRSN' },
 | 
			
		||||
    { value: 'Internet Stream', identifier: 'TRSO' },
 | 
			
		||||
    { value: 'Any Time You Like', identifier: 'TIT2' }
 | 
			
		||||
  ]
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
Platforms: Android ExoPlayer, iOS
 | 
			
		||||
 | 
			
		||||
### Methods
 | 
			
		||||
Methods operate on a ref to the Video element. You can create a ref using code like:
 | 
			
		||||
```
 | 
			
		||||
@@ -558,14 +602,19 @@ For more detailed info check this [article](https://cocoacasts.com/how-to-add-ap
 | 
			
		||||
</details>
 | 
			
		||||
 | 
			
		||||
### Android Expansion File Usage
 | 
			
		||||
Within your render function, assuming you have a file called
 | 
			
		||||
"background.mp4" in your expansion file. Just add your main and (if applicable) patch version
 | 
			
		||||
Expansions files allow you to ship assets that exceed the 100MB apk size limit and don't need to be updated each time you push an app update.
 | 
			
		||||
 | 
			
		||||
This only supports mp4 files and they must not be compressed. Example command line for preventing compression:
 | 
			
		||||
```bash
 | 
			
		||||
zip -r -n .mp4 *.mp4 player.video.example.com
 | 
			
		||||
```
 | 
			
		||||
<Video
 | 
			
		||||
  source={{uri: "background", mainVer: 1, patchVer: 0}}
 | 
			
		||||
/>
 | 
			
		||||
```
 | 
			
		||||
This will look for an .mp4 file (background.mp4) in the given expansion version.
 | 
			
		||||
 | 
			
		||||
```javascript
 | 
			
		||||
// Within your render function, assuming you have a file called
 | 
			
		||||
// "background.mp4" in your expansion file. Just add your main and (if applicable) patch version
 | 
			
		||||
<Video source={{uri: "background", mainVer: 1, patchVer: 0}} // Looks for .mp4 file (background.mp4) in the given expansion version.
 | 
			
		||||
       resizeMode="cover"           // Fill the whole screen at aspect ratio.
 | 
			
		||||
       style={styles.backgroundVideo} />
 | 
			
		||||
 | 
			
		||||
### Load files with the RN Asset System
 | 
			
		||||
 | 
			
		||||
@@ -598,9 +647,49 @@ To enable audio to play in background on iOS the audio session needs to be set t
 | 
			
		||||
 | 
			
		||||
- [Lumpen Radio](https://github.com/jhabdas/lumpen-radio) contains another example integration using local files and full screen background video.
 | 
			
		||||
 | 
			
		||||
## Updating
 | 
			
		||||
 | 
			
		||||
### Version 3.0
 | 
			
		||||
 | 
			
		||||
#### All platforms now auto-play
 | 
			
		||||
Previously, on Android ExoPlayer if the paused prop was not set, the media would not automatically start playing. The only way it would work was if you set `paused={false}`. This has been changed to automatically play if paused is not set so that the behavior is consistent across platforms.
 | 
			
		||||
 | 
			
		||||
#### All platforms now keep their paused state when returning from the background
 | 
			
		||||
Previously, on Android MediaPlayer if you setup an AppState event when the app went into the background and set a paused prop so that when you returned to the app the video would be paused it would be ignored.
 | 
			
		||||
 | 
			
		||||
Note, Windows does not have a concept of an app going into the background, so this doesn't apply there.
 | 
			
		||||
 | 
			
		||||
#### Use Android SDK 27 by default
 | 
			
		||||
Version 3.0 updates the Android build tools and SDK to version 27. React Native is in the process of [switchting over](https://github.com/facebook/react-native/issues/18095#issuecomment-395596130) to SDK 27 in preparation for Google's requirement that new Android apps [use SDK 26](https://android-developers.googleblog.com/2017/12/improving-app-security-and-performance.html) by August 2018.
 | 
			
		||||
 | 
			
		||||
You will either need to install the version 27 SDK and version 27.0.3 buildtools or modify your build.gradle file to configure react-native-video to use the same build settings as the rest of your app as described below.
 | 
			
		||||
 | 
			
		||||
##### Using app build settings
 | 
			
		||||
You will need to create a `project.ext` section in the top-level build.gradle file (not app/build.gradle). Fill in the values from the example below using the values found in your app/build.gradle file.
 | 
			
		||||
```
 | 
			
		||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
 | 
			
		||||
 | 
			
		||||
buildscript {
 | 
			
		||||
    ... // Various other settings go here
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
allprojects {
 | 
			
		||||
    ... // Various other settings go here
 | 
			
		||||
 | 
			
		||||
    project.ext {
 | 
			
		||||
        compileSdkVersion = 23
 | 
			
		||||
        buildToolsVersion = "23.0.1"
 | 
			
		||||
 | 
			
		||||
        minSdkVersion = 16
 | 
			
		||||
        targetSdkVersion = 22
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
If you encounter an error `Could not find com.android.support:support-annotations:27.0.0.` reinstall your Android Support Repository.
 | 
			
		||||
 | 
			
		||||
## TODOS
 | 
			
		||||
 | 
			
		||||
- [ ] Add support for captions
 | 
			
		||||
- [ ] Add support for playing multiple videos in a sequence (will interfere with current `repeat` implementation)
 | 
			
		||||
- [x] Callback to get buffering progress for remote videos
 | 
			
		||||
- [ ] Bring API closer to HTML5 `<Video>` [reference](http://devdocs.io/html/element/video)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										24
									
								
								Video.js
									
									
									
									
									
								
							
							
						
						
									
										24
									
								
								Video.js
									
									
									
									
									
								
							@@ -27,6 +27,29 @@ export default class Video extends Component {
 | 
			
		||||
    this._root.setNativeProps(nativeProps);
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  toTypeString(x) {
 | 
			
		||||
    switch (typeof x) {
 | 
			
		||||
      case "object":
 | 
			
		||||
        return x instanceof Date 
 | 
			
		||||
          ? x.toISOString() 
 | 
			
		||||
          : JSON.stringify(x); // object, null
 | 
			
		||||
      case "undefined":
 | 
			
		||||
        return "";
 | 
			
		||||
      default: // boolean, number, string
 | 
			
		||||
        return x.toString();      
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  stringsOnlyObject(obj) {
 | 
			
		||||
    const strObj = {};
 | 
			
		||||
 | 
			
		||||
    Object.keys(obj).forEach(x => {
 | 
			
		||||
      strObj[x] = this.toTypeString(obj[x]);
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return strObj;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  seek = (time, tolerance = 100) => {
 | 
			
		||||
    if (Platform.OS === 'ios') {
 | 
			
		||||
      this.setNativeProps({
 | 
			
		||||
@@ -202,6 +225,7 @@ export default class Video extends Component {
 | 
			
		||||
        type: source.type || '',
 | 
			
		||||
        mainVer: source.mainVer || 0,
 | 
			
		||||
        patchVer: source.patchVer || 0,
 | 
			
		||||
        requestHeaders: source.headers ? this.stringsOnlyObject(source.headers) : {}
 | 
			
		||||
      },
 | 
			
		||||
      onVideoLoadStart: this._onLoadStart,
 | 
			
		||||
      onVideoLoad: this._onLoad,
 | 
			
		||||
 
 | 
			
		||||
@@ -17,6 +17,8 @@ import com.google.android.exoplayer2.util.Util;
 | 
			
		||||
import okhttp3.Cookie;
 | 
			
		||||
import okhttp3.JavaNetCookieJar;
 | 
			
		||||
import okhttp3.OkHttpClient;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
public class DataSourceUtil {
 | 
			
		||||
 | 
			
		||||
@@ -49,9 +51,10 @@ public class DataSourceUtil {
 | 
			
		||||
        DataSourceUtil.rawDataSourceFactory = factory;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static DataSource.Factory getDefaultDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter) {
 | 
			
		||||
        if (defaultDataSourceFactory == null) {
 | 
			
		||||
            defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter);
 | 
			
		||||
 | 
			
		||||
    public static DataSource.Factory getDefaultDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map<String, String> requestHeaders) {
 | 
			
		||||
        if (defaultDataSourceFactory == null || (requestHeaders != null && !requestHeaders.isEmpty())) {
 | 
			
		||||
            defaultDataSourceFactory = buildDataSourceFactory(context, bandwidthMeter, requestHeaders);
 | 
			
		||||
        }
 | 
			
		||||
        return defaultDataSourceFactory;
 | 
			
		||||
    }
 | 
			
		||||
@@ -64,17 +67,21 @@ public class DataSourceUtil {
 | 
			
		||||
        return new RawResourceDataSourceFactory(context.getApplicationContext());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static DataSource.Factory buildDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter) {
 | 
			
		||||
    private static DataSource.Factory buildDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map<String, String> requestHeaders) {
 | 
			
		||||
        return new DefaultDataSourceFactory(context, bandwidthMeter,
 | 
			
		||||
                buildHttpDataSourceFactory(context, bandwidthMeter));
 | 
			
		||||
                buildHttpDataSourceFactory(context, bandwidthMeter, requestHeaders));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private static HttpDataSource.Factory buildHttpDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter) {
 | 
			
		||||
    private static HttpDataSource.Factory buildHttpDataSourceFactory(ReactContext context, DefaultBandwidthMeter bandwidthMeter, Map<String, String> requestHeaders) {
 | 
			
		||||
        OkHttpClient client = OkHttpClientProvider.getOkHttpClient();
 | 
			
		||||
        CookieJarContainer container = (CookieJarContainer) client.cookieJar();
 | 
			
		||||
        ForwardingCookieHandler handler = new ForwardingCookieHandler(context);
 | 
			
		||||
        container.setCookieJar(new JavaNetCookieJar(handler));
 | 
			
		||||
        return new OkHttpDataSourceFactory(client, getUserAgent(context), bandwidthMeter);
 | 
			
		||||
    }
 | 
			
		||||
        OkHttpDataSourceFactory okHttpDataSourceFactory = new OkHttpDataSourceFactory(client, getUserAgent(context), bandwidthMeter);
 | 
			
		||||
 | 
			
		||||
        if (requestHeaders != null)
 | 
			
		||||
            okHttpDataSourceFactory.getDefaultRequestProperties().set(requestHeaders);
 | 
			
		||||
 | 
			
		||||
        return okHttpDataSourceFactory;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -66,6 +66,7 @@ import java.net.CookieHandler;
 | 
			
		||||
import java.net.CookieManager;
 | 
			
		||||
import java.net.CookiePolicy;
 | 
			
		||||
import java.lang.Math;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
import java.lang.Object;
 | 
			
		||||
import java.util.ArrayList;
 | 
			
		||||
 | 
			
		||||
@@ -103,7 +104,7 @@ class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
    private boolean loadVideoStarted;
 | 
			
		||||
    private boolean isFullscreen;
 | 
			
		||||
    private boolean isInBackground;
 | 
			
		||||
    private boolean isPaused = true;
 | 
			
		||||
    private boolean isPaused;
 | 
			
		||||
    private boolean isBuffering;
 | 
			
		||||
    private float rate = 1f;
 | 
			
		||||
 | 
			
		||||
@@ -118,6 +119,7 @@ class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
    private float mProgressUpdateInterval = 250.0f;
 | 
			
		||||
    private boolean playInBackground = false;
 | 
			
		||||
    private boolean useTextureView = false;
 | 
			
		||||
    private Map<String, String> requestHeaders;
 | 
			
		||||
    // \ End props
 | 
			
		||||
 | 
			
		||||
    // React
 | 
			
		||||
@@ -135,7 +137,7 @@ class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
                            && player.getPlayWhenReady()
 | 
			
		||||
                            ) {
 | 
			
		||||
                        long pos = player.getCurrentPosition();
 | 
			
		||||
                        long bufferedDuration = player.getBufferedPercentage() * player.getDuration();
 | 
			
		||||
                        long bufferedDuration = player.getBufferedPercentage() * player.getDuration() / 100;
 | 
			
		||||
                        eventEmitter.progressChanged(pos, bufferedDuration, player.getDuration());
 | 
			
		||||
                        msg = obtainMessage(SHOW_PROGRESS);
 | 
			
		||||
                        sendMessageDelayed(msg, Math.round(mProgressUpdateInterval));
 | 
			
		||||
@@ -417,7 +419,7 @@ class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
     * @return A new DataSource factory.
 | 
			
		||||
     */
 | 
			
		||||
    private DataSource.Factory buildDataSourceFactory(boolean useBandwidthMeter) {
 | 
			
		||||
        return DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, useBandwidthMeter ? BANDWIDTH_METER : null);
 | 
			
		||||
        return DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, useBandwidthMeter ? BANDWIDTH_METER : null, requestHeaders);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // AudioManager.OnAudioFocusChangeListener implementation
 | 
			
		||||
@@ -661,14 +663,15 @@ class ReactExoplayerView extends FrameLayout implements
 | 
			
		||||
 | 
			
		||||
    // ReactExoplayerViewManager public api
 | 
			
		||||
 | 
			
		||||
    public void setSrc(final Uri uri, final String extension) {
 | 
			
		||||
    public void setSrc(final Uri uri, final String extension, Map<String, String> headers) {
 | 
			
		||||
        if (uri != null) {
 | 
			
		||||
            boolean isOriginalSourceNull = srcUri == null;
 | 
			
		||||
            boolean isSourceEqual = uri.equals(srcUri);
 | 
			
		||||
 | 
			
		||||
            this.srcUri = uri;
 | 
			
		||||
            this.extension = extension;
 | 
			
		||||
            this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, BANDWIDTH_METER);
 | 
			
		||||
            this.requestHeaders = headers;
 | 
			
		||||
            this.mediaDataSourceFactory = DataSourceUtil.getDefaultDataSourceFactory(this.themedReactContext, BANDWIDTH_METER, this.requestHeaders);
 | 
			
		||||
 | 
			
		||||
            if (!isOriginalSourceNull && !isSourceEqual) {
 | 
			
		||||
                reloadSource();
 | 
			
		||||
 
 | 
			
		||||
@@ -13,6 +13,7 @@ import com.facebook.react.uimanager.ViewGroupManager;
 | 
			
		||||
import com.facebook.react.uimanager.annotations.ReactProp;
 | 
			
		||||
import com.google.android.exoplayer2.upstream.RawResourceDataSource;
 | 
			
		||||
 | 
			
		||||
import java.util.HashMap;
 | 
			
		||||
import java.util.Map;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
@@ -24,6 +25,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
 | 
			
		||||
    private static final String PROP_SRC = "src";
 | 
			
		||||
    private static final String PROP_SRC_URI = "uri";
 | 
			
		||||
    private static final String PROP_SRC_TYPE = "type";
 | 
			
		||||
    private static final String PROP_SRC_HEADERS = "requestHeaders";
 | 
			
		||||
    private static final String PROP_RESIZE_MODE = "resizeMode";
 | 
			
		||||
    private static final String PROP_REPEAT = "repeat";
 | 
			
		||||
    private static final String PROP_SELECTED_TEXT_TRACK = "selectedTextTrack";
 | 
			
		||||
@@ -80,6 +82,8 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
 | 
			
		||||
        Context context = videoView.getContext().getApplicationContext();
 | 
			
		||||
        String uriString = src.hasKey(PROP_SRC_URI) ? src.getString(PROP_SRC_URI) : null;
 | 
			
		||||
        String extension = src.hasKey(PROP_SRC_TYPE) ? src.getString(PROP_SRC_TYPE) : null;
 | 
			
		||||
        Map<String, String> headers = src.hasKey(PROP_SRC_HEADERS) ? toStringMap(src.getMap(PROP_SRC_HEADERS)) : null;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
        if (TextUtils.isEmpty(uriString)) {
 | 
			
		||||
            return;
 | 
			
		||||
@@ -89,7 +93,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
 | 
			
		||||
            Uri srcUri = Uri.parse(uriString);
 | 
			
		||||
 | 
			
		||||
            if (srcUri != null) {
 | 
			
		||||
                videoView.setSrc(srcUri, extension);
 | 
			
		||||
                videoView.setSrc(srcUri, extension, headers);
 | 
			
		||||
            }
 | 
			
		||||
        } else {
 | 
			
		||||
            int identifier = context.getResources().getIdentifier(
 | 
			
		||||
@@ -208,4 +212,28 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
 | 
			
		||||
        }
 | 
			
		||||
        return ResizeMode.RESIZE_MODE_FIT;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * toStringMap converts a {@link ReadableMap} into a HashMap.
 | 
			
		||||
     *
 | 
			
		||||
     * @param readableMap The ReadableMap to be conveted.
 | 
			
		||||
     * @return A HashMap containing the data that was in the ReadableMap.
 | 
			
		||||
     * @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java'
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, String> toStringMap(@Nullable ReadableMap readableMap) {
 | 
			
		||||
        if (readableMap == null)
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        com.facebook.react.bridge.ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
 | 
			
		||||
        if (!iterator.hasNextKey())
 | 
			
		||||
            return null;
 | 
			
		||||
 | 
			
		||||
        Map<String, String> result = new HashMap<>();
 | 
			
		||||
        while (iterator.hasNextKey()) {
 | 
			
		||||
            String key = iterator.nextKey();
 | 
			
		||||
            result.put(key, readableMap.getString(key));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@ import com.android.vending.expansion.zipfile.APKExpansionSupport;
 | 
			
		||||
import com.android.vending.expansion.zipfile.ZipResourceFile;
 | 
			
		||||
import com.facebook.react.bridge.Arguments;
 | 
			
		||||
import com.facebook.react.bridge.LifecycleEventListener;
 | 
			
		||||
import com.facebook.react.bridge.ReadableMap;
 | 
			
		||||
import com.facebook.react.bridge.WritableMap;
 | 
			
		||||
import com.facebook.react.uimanager.ThemedReactContext;
 | 
			
		||||
import com.facebook.react.uimanager.events.RCTEventEmitter;
 | 
			
		||||
@@ -30,6 +31,8 @@ import java.util.Map;
 | 
			
		||||
import java.lang.Math;
 | 
			
		||||
import java.math.BigDecimal;
 | 
			
		||||
 | 
			
		||||
import javax.annotation.Nullable;
 | 
			
		||||
 | 
			
		||||
@SuppressLint("ViewConstructor")
 | 
			
		||||
public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnPreparedListener, MediaPlayer
 | 
			
		||||
        .OnErrorListener, MediaPlayer.OnBufferingUpdateListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnInfoListener, LifecycleEventListener, MediaController.MediaPlayerControl {
 | 
			
		||||
@@ -89,6 +92,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
 | 
			
		||||
 | 
			
		||||
    private String mSrcUriString = null;
 | 
			
		||||
    private String mSrcType = "mp4";
 | 
			
		||||
    private ReadableMap mRequestHeaders = null;
 | 
			
		||||
    private boolean mSrcIsNetwork = false;
 | 
			
		||||
    private boolean mSrcIsAsset = false;
 | 
			
		||||
    private ScalableType mResizeMode = ScalableType.LEFT_TOP;
 | 
			
		||||
@@ -101,8 +105,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
 | 
			
		||||
    private float mRate = 1.0f;
 | 
			
		||||
    private float mActiveRate = 1.0f;
 | 
			
		||||
    private boolean mPlayInBackground = false;
 | 
			
		||||
    private boolean mActiveStatePauseStatus = false;
 | 
			
		||||
    private boolean mActiveStatePauseStatusInitialized = false;
 | 
			
		||||
    private boolean mBackgroundPaused = false;
 | 
			
		||||
 | 
			
		||||
    private int mMainVer = 0;
 | 
			
		||||
    private int mPatchVer = 0;
 | 
			
		||||
@@ -128,7 +131,7 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
 | 
			
		||||
            @Override
 | 
			
		||||
            public void run() {
 | 
			
		||||
 | 
			
		||||
                if (mMediaPlayerValid && !isCompleted &&!mPaused) {
 | 
			
		||||
                if (mMediaPlayerValid && !isCompleted && !mPaused && !mBackgroundPaused) {
 | 
			
		||||
                    WritableMap event = Arguments.createMap();
 | 
			
		||||
                    event.putDouble(EVENT_PROP_CURRENT_TIME, mMediaPlayer.getCurrentPosition() / 1000.0);
 | 
			
		||||
                    event.putDouble(EVENT_PROP_PLAYABLE_DURATION, mVideoBufferedDuration / 1000.0); //TODO:mBufferUpdateRunnable
 | 
			
		||||
@@ -207,16 +210,17 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset) {
 | 
			
		||||
        setSrc(uriString,type,isNetwork,isAsset,0,0);
 | 
			
		||||
    public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders) {
 | 
			
		||||
        setSrc(uriString, type, isNetwork, isAsset, requestHeaders, 0, 0);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final int expansionMainVersion, final int expansionPatchVersion) {
 | 
			
		||||
    public void setSrc(final String uriString, final String type, final boolean isNetwork, final boolean isAsset, final ReadableMap requestHeaders, final int expansionMainVersion, final int expansionPatchVersion) {
 | 
			
		||||
 | 
			
		||||
        mSrcUriString = uriString;
 | 
			
		||||
        mSrcType = type;
 | 
			
		||||
        mSrcIsNetwork = isNetwork;
 | 
			
		||||
        mSrcIsAsset = isAsset;
 | 
			
		||||
        mRequestHeaders = requestHeaders;
 | 
			
		||||
        mMainVer = expansionMainVersion;
 | 
			
		||||
        mPatchVer = expansionPatchVersion;
 | 
			
		||||
 | 
			
		||||
@@ -245,7 +249,15 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
 | 
			
		||||
                    headers.put("Cookie", cookie);
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                setDataSource(uriString);
 | 
			
		||||
                if (mRequestHeaders != null) {
 | 
			
		||||
                    headers.putAll(toStringMap(mRequestHeaders));
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                /* According to https://github.com/react-native-community/react-native-video/pull/537
 | 
			
		||||
                 *   there is an issue with this where it can cause a IOException.
 | 
			
		||||
                 * TODO: diagnose this exception and fix it
 | 
			
		||||
                 */
 | 
			
		||||
                setDataSource(mThemedReactContext, parsedUrl, headers);
 | 
			
		||||
            } else if (isAsset) {
 | 
			
		||||
                if (uriString.startsWith("content://")) {
 | 
			
		||||
                    Uri parsedUrl = Uri.parse(uriString);
 | 
			
		||||
@@ -291,8 +303,13 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        WritableMap src = Arguments.createMap();
 | 
			
		||||
 | 
			
		||||
        WritableMap wRequestHeaders = Arguments.createMap();
 | 
			
		||||
        wRequestHeaders.merge(mRequestHeaders);
 | 
			
		||||
 | 
			
		||||
        src.putString(ReactVideoViewManager.PROP_SRC_URI, uriString);
 | 
			
		||||
        src.putString(ReactVideoViewManager.PROP_SRC_TYPE, type);
 | 
			
		||||
        src.putMap(ReactVideoViewManager.PROP_SRC_HEADERS, wRequestHeaders);
 | 
			
		||||
        src.putBoolean(ReactVideoViewManager.PROP_SRC_IS_NETWORK, isNetwork);
 | 
			
		||||
        if(mMainVer>0) {
 | 
			
		||||
            src.putInt(ReactVideoViewManager.PROP_SRC_MAINVER, mMainVer);
 | 
			
		||||
@@ -334,11 +351,6 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
 | 
			
		||||
 | 
			
		||||
        mPaused = paused;
 | 
			
		||||
 | 
			
		||||
        if ( !mActiveStatePauseStatusInitialized ) {
 | 
			
		||||
            mActiveStatePauseStatus = mPaused;
 | 
			
		||||
            mActiveStatePauseStatusInitialized = true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!mMediaPlayerValid) {
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
@@ -410,8 +422,16 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
 | 
			
		||||
        if (mMediaPlayerValid) {
 | 
			
		||||
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
 | 
			
		||||
                if (!mPaused) { // Applying the rate while paused will cause the video to start
 | 
			
		||||
                    /* Per https://stackoverflow.com/questions/39442522/setplaybackparams-causes-illegalstateexception
 | 
			
		||||
                     * Some devices throw an IllegalStateException if you set the rate without first calling reset()
 | 
			
		||||
                     * TODO: Call reset() then reinitialize the player
 | 
			
		||||
                     */
 | 
			
		||||
                    try {
 | 
			
		||||
                        mMediaPlayer.setPlaybackParams(mMediaPlayer.getPlaybackParams().setSpeed(rate));
 | 
			
		||||
                        mActiveRate = rate;
 | 
			
		||||
                    } catch (Exception e) {
 | 
			
		||||
                        Log.e(ReactVideoViewManager.REACT_CLASS, "Unable to set rate, unsupported on this device");
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            } else {
 | 
			
		||||
                Log.e(ReactVideoViewManager.REACT_CLASS, "Setting playback rate is not yet supported on Android versions below 6.0");
 | 
			
		||||
@@ -579,39 +599,62 @@ public class ReactVideoView extends ScalableVideoView implements MediaPlayer.OnP
 | 
			
		||||
        super.onAttachedToWindow();
 | 
			
		||||
 | 
			
		||||
        if(mMainVer>0) {
 | 
			
		||||
            setSrc(mSrcUriString, mSrcType, mSrcIsNetwork,mSrcIsAsset,mMainVer,mPatchVer);
 | 
			
		||||
            setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders, mMainVer, mPatchVer);
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            setSrc(mSrcUriString, mSrcType, mSrcIsNetwork,mSrcIsAsset);
 | 
			
		||||
            setSrc(mSrcUriString, mSrcType, mSrcIsNetwork, mSrcIsAsset, mRequestHeaders);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onHostPause() {
 | 
			
		||||
        if (mMediaPlayer != null && !mPlayInBackground) {
 | 
			
		||||
            mActiveStatePauseStatus = mPaused;
 | 
			
		||||
 | 
			
		||||
            // Pause the video in background
 | 
			
		||||
            setPausedModifier(true);
 | 
			
		||||
        if (mMediaPlayerValid && !mPaused && !mPlayInBackground) {
 | 
			
		||||
            /* Pause the video in background
 | 
			
		||||
             * Don't update the paused prop, developers should be able to update it on background
 | 
			
		||||
             *  so that when you return to the app the video is paused
 | 
			
		||||
             */
 | 
			
		||||
            mBackgroundPaused = true;
 | 
			
		||||
            mMediaPlayer.pause();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onHostResume() {
 | 
			
		||||
        if (mMediaPlayer != null && !mPlayInBackground) {
 | 
			
		||||
        mBackgroundPaused = false;
 | 
			
		||||
        if (mMediaPlayerValid && !mPlayInBackground && !mPaused) {
 | 
			
		||||
            new Handler().post(new Runnable() {
 | 
			
		||||
                @Override
 | 
			
		||||
                public void run() {
 | 
			
		||||
                    // Restore original state
 | 
			
		||||
                    setPausedModifier(mActiveStatePauseStatus);
 | 
			
		||||
                    setPausedModifier(false);
 | 
			
		||||
                }
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    @Override
 | 
			
		||||
    public void onHostDestroy() {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * toStringMap converts a {@link ReadableMap} into a HashMap.
 | 
			
		||||
     *
 | 
			
		||||
     * @param readableMap The ReadableMap to be conveted.
 | 
			
		||||
     * @return A HashMap containing the data that was in the ReadableMap.
 | 
			
		||||
     * @see 'Adapted from https://github.com/artemyarulin/react-native-eval/blob/master/android/src/main/java/com/evaluator/react/ConversionUtil.java'
 | 
			
		||||
     */
 | 
			
		||||
    public static Map<String, String> toStringMap(@Nullable ReadableMap readableMap) {
 | 
			
		||||
        Map<String, String> result = new HashMap<>();
 | 
			
		||||
        if (readableMap == null)
 | 
			
		||||
            return result;
 | 
			
		||||
 | 
			
		||||
        com.facebook.react.bridge.ReadableMapKeySetIterator iterator = readableMap.keySetIterator();
 | 
			
		||||
        while (iterator.hasNextKey()) {
 | 
			
		||||
            String key = iterator.nextKey();
 | 
			
		||||
            result.put(key, readableMap.getString(key));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -21,6 +21,7 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
 | 
			
		||||
    public static final String PROP_SRC = "src";
 | 
			
		||||
    public static final String PROP_SRC_URI = "uri";
 | 
			
		||||
    public static final String PROP_SRC_TYPE = "type";
 | 
			
		||||
    public static final String PROP_SRC_HEADERS = "requestHeaders";
 | 
			
		||||
    public static final String PROP_SRC_IS_NETWORK = "isNetwork";
 | 
			
		||||
    public static final String PROP_SRC_MAINVER = "mainVer";
 | 
			
		||||
    public static final String PROP_SRC_PATCHVER = "patchVer";
 | 
			
		||||
@@ -86,6 +87,7 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
 | 
			
		||||
                    src.getString(PROP_SRC_TYPE),
 | 
			
		||||
                    src.getBoolean(PROP_SRC_IS_NETWORK),
 | 
			
		||||
                    src.getBoolean(PROP_SRC_IS_ASSET),
 | 
			
		||||
                    src.getMap(PROP_SRC_HEADERS),
 | 
			
		||||
                    mainVer,
 | 
			
		||||
                    patchVer
 | 
			
		||||
            );
 | 
			
		||||
@@ -95,7 +97,8 @@ public class ReactVideoViewManager extends SimpleViewManager<ReactVideoView> {
 | 
			
		||||
                    src.getString(PROP_SRC_URI),
 | 
			
		||||
                    src.getString(PROP_SRC_TYPE),
 | 
			
		||||
                    src.getBoolean(PROP_SRC_IS_NETWORK),
 | 
			
		||||
                    src.getBoolean(PROP_SRC_IS_ASSET)
 | 
			
		||||
                    src.getBoolean(PROP_SRC_IS_ASSET),
 | 
			
		||||
                    src.getMap(PROP_SRC_HEADERS)
 | 
			
		||||
                    );
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -26,6 +26,7 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
			
		||||
  /* Required to publish events */
 | 
			
		||||
  RCTEventDispatcher *_eventDispatcher;
 | 
			
		||||
  BOOL _playbackRateObserverRegistered;
 | 
			
		||||
  BOOL _videoLoadStarted;
 | 
			
		||||
 | 
			
		||||
  bool _pendingSeek;
 | 
			
		||||
  float _pendingSeekTime;
 | 
			
		||||
@@ -96,7 +97,7 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
			
		||||
 | 
			
		||||
- (AVPlayerViewController*)createPlayerViewController:(AVPlayer*)player withPlayerItem:(AVPlayerItem*)playerItem {
 | 
			
		||||
    RCTVideoPlayerViewController* playerLayer= [[RCTVideoPlayerViewController alloc] init];
 | 
			
		||||
    playerLayer.showsPlaybackControls = NO;
 | 
			
		||||
    playerLayer.showsPlaybackControls = YES;
 | 
			
		||||
    playerLayer.rctDelegate = self;
 | 
			
		||||
    playerLayer.view.frame = self.bounds;
 | 
			
		||||
    playerLayer.player = player;
 | 
			
		||||
@@ -324,6 +325,7 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
			
		||||
        }
 | 
			
		||||
    });
 | 
			
		||||
  });
 | 
			
		||||
  _videoLoadStarted = YES;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
- (NSURL*) urlFilePath:(NSString*) filepath {
 | 
			
		||||
@@ -350,14 +352,24 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
			
		||||
  NSString *uri = [source objectForKey:@"uri"];
 | 
			
		||||
  NSString *subtitleUri = _selectedTextTrack[@"uri"];
 | 
			
		||||
  NSString *type = [source objectForKey:@"type"];
 | 
			
		||||
  NSDictionary *headers = [source objectForKey:@"requestHeaders"];
 | 
			
		||||
 | 
			
		||||
  AVURLAsset *asset;
 | 
			
		||||
  AVURLAsset *subAsset;
 | 
			
		||||
 | 
			
		||||
  if (isNetwork) {
 | 
			
		||||
    NSMutableDictionary *assetOptions = [[NSMutableDictionary alloc]init];
 | 
			
		||||
    /* Per #1091, this is not a public API. We need to either get approval from Apple to use this
 | 
			
		||||
     * or use a different approach.
 | 
			
		||||
    if ([headers count] > 0) {
 | 
			
		||||
      [assetOptions setObject:headers forKey:@"AVURLAssetHTTPHeaderFieldsKey"];
 | 
			
		||||
    }
 | 
			
		||||
    */
 | 
			
		||||
    NSArray *cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies];
 | 
			
		||||
    asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:uri] options:@{AVURLAssetHTTPCookiesKey : cookies}];
 | 
			
		||||
    subAsset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:subtitleUri] options:@{AVURLAssetHTTPCookiesKey : cookies}];
 | 
			
		||||
    [assetOptions setObject:cookies forKey:AVURLAssetHTTPCookiesKey];
 | 
			
		||||
 | 
			
		||||
    asset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:uri] options:assetOptions];
 | 
			
		||||
    subAsset = [AVURLAsset URLAssetWithURL:[NSURL URLWithString:subtitleUri] options:assetOptions];
 | 
			
		||||
  }
 | 
			
		||||
  else if (isAsset) //  assets on iOS have to be in the Documents folder
 | 
			
		||||
  {
 | 
			
		||||
@@ -405,18 +417,12 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
			
		||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
 | 
			
		||||
{
 | 
			
		||||
  if (object == _playerItem) {
 | 
			
		||||
 | 
			
		||||
    // When timeMetadata is read the event onTimedMetadata is triggered
 | 
			
		||||
    if ([keyPath isEqualToString: timedMetadata])
 | 
			
		||||
    {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    if ([keyPath isEqualToString:timedMetadata]) {
 | 
			
		||||
      NSArray<AVMetadataItem *> *items = [change objectForKey:@"new"];
 | 
			
		||||
      if (items && ![items isEqual:[NSNull null]] && items.count > 0) {
 | 
			
		||||
 | 
			
		||||
        NSMutableArray *array = [NSMutableArray new];
 | 
			
		||||
        for (AVMetadataItem *item in items) {
 | 
			
		||||
 | 
			
		||||
          NSString *value = item.value;
 | 
			
		||||
          NSString *identifier = item.identifier;
 | 
			
		||||
          
 | 
			
		||||
@@ -448,22 +454,24 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
			
		||||
        NSString *orientation = @"undefined";
 | 
			
		||||
        
 | 
			
		||||
        if ([_playerItem.asset tracksWithMediaType:AVMediaTypeVideo].count > 0) {
 | 
			
		||||
          AVAssetTrack *videoAsset = [[_playerItem.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
 | 
			
		||||
 | 
			
		||||
          width = [NSNumber numberWithFloat:videoAsset.naturalSize.width];
 | 
			
		||||
          height = [NSNumber numberWithFloat:videoAsset.naturalSize.height];
 | 
			
		||||
          CGAffineTransform preferredTransform = [videoAsset preferredTransform];
 | 
			
		||||
          AVAssetTrack *videoTrack = [[_playerItem.asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
 | 
			
		||||
          width = [NSNumber numberWithFloat:videoTrack.naturalSize.width];
 | 
			
		||||
          height = [NSNumber numberWithFloat:videoTrack.naturalSize.height];
 | 
			
		||||
          CGAffineTransform preferredTransform = [videoTrack preferredTransform];
 | 
			
		||||
          
 | 
			
		||||
          if ((videoAsset.naturalSize.width == preferredTransform.tx
 | 
			
		||||
            && videoAsset.naturalSize.height == preferredTransform.ty)
 | 
			
		||||
          if ((videoTrack.naturalSize.width == preferredTransform.tx
 | 
			
		||||
               && videoTrack.naturalSize.height == preferredTransform.ty)
 | 
			
		||||
              || (preferredTransform.tx == 0 && preferredTransform.ty == 0))
 | 
			
		||||
 | 
			
		||||
          {
 | 
			
		||||
            orientation = @"landscape";
 | 
			
		||||
          } else
 | 
			
		||||
          } else {
 | 
			
		||||
            orientation = @"portrait";
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
        
 | 
			
		||||
      if(self.onVideoLoad) {
 | 
			
		||||
        if (self.onVideoLoad && _videoLoadStarted) {
 | 
			
		||||
          self.onVideoLoad(@{@"duration": [NSNumber numberWithFloat:duration],
 | 
			
		||||
                             @"currentTime": [NSNumber numberWithFloat:CMTimeGetSeconds(_playerItem.currentTime)],
 | 
			
		||||
                             @"canPlayReverse": [NSNumber numberWithBool:_playerItem.canPlayReverse],
 | 
			
		||||
@@ -480,11 +488,11 @@ static NSString *const timedMetadata = @"timedMetadata";
 | 
			
		||||
                             @"textTracks": [self getTextTrackInfo],
 | 
			
		||||
                             @"target": self.reactTag});
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        _videoLoadStarted = NO;
 | 
			
		||||
        
 | 
			
		||||
        [self attachListeners];
 | 
			
		||||
        [self applyModifiers];
 | 
			
		||||
      } else if(_playerItem.status == AVPlayerItemStatusFailed && self.onVideoError) {
 | 
			
		||||
      } else if (_playerItem.status == AVPlayerItemStatusFailed && self.onVideoError) {
 | 
			
		||||
        self.onVideoError(@{@"error": @{@"code": [NSNumber numberWithInteger: _playerItem.error.code],
 | 
			
		||||
                                        @"domain": _playerItem.error.domain},
 | 
			
		||||
                            @"target": self.reactTag});
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										74
									
								
								package.json
									
									
									
									
									
								
							
							
						
						
									
										74
									
								
								package.json
									
									
									
									
									
								
							@@ -1,38 +1,10 @@
 | 
			
		||||
{
 | 
			
		||||
  "_args": [
 | 
			
		||||
    [
 | 
			
		||||
      "git://github.com/nfb-onf/react-native-video.git",
 | 
			
		||||
      "/Users/amishra/Development/react_films"
 | 
			
		||||
    ]
 | 
			
		||||
  ],
 | 
			
		||||
  "_from": "git://github.com/nfb-onf/react-native-video.git",
 | 
			
		||||
  "_id": "react-native-video@git://github.com/nfb-onf/react-native-video.git#8ce39e5b82108e6b9ea8549bd72ba58e95f04647",
 | 
			
		||||
  "_inBundle": false,
 | 
			
		||||
  "_integrity": "",
 | 
			
		||||
  "_location": "/react-native-video",
 | 
			
		||||
  "_phantomChildren": {},
 | 
			
		||||
  "_requested": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "raw": "git://github.com/nfb-onf/react-native-video.git",
 | 
			
		||||
    "rawSpec": "git://github.com/nfb-onf/react-native-video.git",
 | 
			
		||||
    "saveSpec": "git://github.com/nfb-onf/react-native-video.git",
 | 
			
		||||
    "fetchSpec": "git://github.com/nfb-onf/react-native-video.git",
 | 
			
		||||
    "gitCommittish": null
 | 
			
		||||
  },
 | 
			
		||||
  "_requiredBy": [
 | 
			
		||||
    "/"
 | 
			
		||||
  ],
 | 
			
		||||
  "_resolved": "git://github.com/nfb-onf/react-native-video.git#8ce39e5b82108e6b9ea8549bd72ba58e95f04647",
 | 
			
		||||
  "_spec": "git://github.com/nfb-onf/react-native-video.git",
 | 
			
		||||
  "_where": "/Users/amishra/Development/react_films",
 | 
			
		||||
  "author": {
 | 
			
		||||
    "name": "Brent Vatne",
 | 
			
		||||
    "email": "brentvatne@gmail.com",
 | 
			
		||||
    "url": "https://github.com/brentvatne"
 | 
			
		||||
  },
 | 
			
		||||
  "bugs": {
 | 
			
		||||
    "url": "https://github.com/brentvatne/react-native-video/issues"
 | 
			
		||||
  },
 | 
			
		||||
    "name": "react-native-video",
 | 
			
		||||
    "version": "3.0.0",
 | 
			
		||||
    "description": "A <Video /> element for react-native",
 | 
			
		||||
    "main": "Video.js",
 | 
			
		||||
    "license": "MIT",
 | 
			
		||||
    "author": "Brent Vatne <brentvatne@gmail.com> (https://github.com/brentvatne)",
 | 
			
		||||
    "contributors": [
 | 
			
		||||
        {
 | 
			
		||||
            "name": "Isaiah Grey",
 | 
			
		||||
@@ -51,33 +23,27 @@
 | 
			
		||||
            "email": "me@hamptonmaxwell.com"
 | 
			
		||||
        }
 | 
			
		||||
    ],
 | 
			
		||||
    "repository": {
 | 
			
		||||
        "type": "git",
 | 
			
		||||
        "url": "git@github.com:brentvatne/react-native-video.git"
 | 
			
		||||
    },
 | 
			
		||||
    "devDependencies": {
 | 
			
		||||
        "jest-cli": "0.2.1",
 | 
			
		||||
        "eslint": "1.10.3",
 | 
			
		||||
        "babel-eslint": "5.0.0-beta8",
 | 
			
		||||
        "eslint-plugin-react": "3.16.1",
 | 
			
		||||
        "eslint-config-airbnb": "4.0.0"
 | 
			
		||||
    },
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "keymirror": "0.1.1",
 | 
			
		||||
        "prop-types": "^15.5.10"
 | 
			
		||||
    },
 | 
			
		||||
  "description": "A <Video /> element for react-native",
 | 
			
		||||
  "devDependencies": {
 | 
			
		||||
    "babel-eslint": "5.0.0-beta8",
 | 
			
		||||
    "eslint": "1.10.3",
 | 
			
		||||
    "eslint-config-airbnb": "4.0.0",
 | 
			
		||||
    "eslint-plugin-react": "3.16.1",
 | 
			
		||||
    "jest-cli": "0.2.1"
 | 
			
		||||
  },
 | 
			
		||||
  "homepage": "https://github.com/brentvatne/react-native-video#readme",
 | 
			
		||||
  "license": "MIT",
 | 
			
		||||
  "main": "Video.js",
 | 
			
		||||
  "name": "react-native-video",
 | 
			
		||||
  "repository": {
 | 
			
		||||
    "type": "git",
 | 
			
		||||
    "url": "git+ssh://git@github.com/brentvatne/react-native-video.git"
 | 
			
		||||
    "scripts": {
 | 
			
		||||
        "test": "node_modules/.bin/eslint *.js"
 | 
			
		||||
    },
 | 
			
		||||
    "rnpm": {
 | 
			
		||||
        "android": {
 | 
			
		||||
            "sourceDir": "./android-exoplayer"
 | 
			
		||||
        }
 | 
			
		||||
  },
 | 
			
		||||
  "scripts": {
 | 
			
		||||
    "test": "eslint *.js"
 | 
			
		||||
  },
 | 
			
		||||
  "version": "2.2.0"
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user