feat: implement startPosition (#3355)
* feat(android): implement startPosition * feat(ios): implement startPosition * feat: implement startPosition type * docs: fix typo * docs: update startPosition * refactor: put startPosition inside source prop - put startPosition inside source prop - rename existing prop (startTime, endTime) * docs: update startPosition property description * fix: fix invalid assignments * refactor: remove redundant optional chaining * feat: allow "0" to work too
This commit is contained in:
parent
0c0f3174cb
commit
2648502b36
@ -192,8 +192,9 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
// Props from React
|
// Props from React
|
||||||
private int backBufferDurationMs = DefaultLoadControl.DEFAULT_BACK_BUFFER_DURATION_MS;
|
private int backBufferDurationMs = DefaultLoadControl.DEFAULT_BACK_BUFFER_DURATION_MS;
|
||||||
private Uri srcUri;
|
private Uri srcUri;
|
||||||
private long startTimeMs = -1;
|
private long startPositionMs = -1;
|
||||||
private long endTimeMs = -1;
|
private long cropStartMs = -1;
|
||||||
|
private long cropEndMs = -1;
|
||||||
private String extension;
|
private String extension;
|
||||||
private boolean repeat;
|
private boolean repeat;
|
||||||
private String audioTrackType;
|
private String audioTrackType;
|
||||||
@ -662,7 +663,7 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
|
|
||||||
private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager drmSessionManager) {
|
private void initializePlayerSource(ReactExoplayerView self, DrmSessionManager drmSessionManager) {
|
||||||
ArrayList<MediaSource> mediaSourceList = buildTextSources();
|
ArrayList<MediaSource> mediaSourceList = buildTextSources();
|
||||||
MediaSource videoSource = buildMediaSource(self.srcUri, self.extension, drmSessionManager, startTimeMs, endTimeMs);
|
MediaSource videoSource = buildMediaSource(self.srcUri, self.extension, drmSessionManager, cropStartMs, cropEndMs);
|
||||||
MediaSource mediaSourceWithAds = null;
|
MediaSource mediaSourceWithAds = null;
|
||||||
if (adTagUrl != null) {
|
if (adTagUrl != null) {
|
||||||
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory)
|
MediaSource.Factory mediaSourceFactory = new DefaultMediaSourceFactory(mediaDataSourceFactory)
|
||||||
@ -703,7 +704,12 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
if (haveResumePosition) {
|
if (haveResumePosition) {
|
||||||
player.seekTo(resumeWindow, resumePosition);
|
player.seekTo(resumeWindow, resumePosition);
|
||||||
}
|
}
|
||||||
player.prepare(mediaSource, !haveResumePosition, false);
|
if (startPositionMs >= 0) {
|
||||||
|
player.setMediaSource(mediaSource, startPositionMs);
|
||||||
|
} else {
|
||||||
|
player.setMediaSource(mediaSource, !haveResumePosition);
|
||||||
|
}
|
||||||
|
player.prepare();
|
||||||
playerNeedsSource = false;
|
playerNeedsSource = false;
|
||||||
|
|
||||||
reLayout(exoPlayerView);
|
reLayout(exoPlayerView);
|
||||||
@ -761,7 +767,7 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager, long startTimeMs, long endTimeMs) {
|
private MediaSource buildMediaSource(Uri uri, String overrideExtension, DrmSessionManager drmSessionManager, long cropStartMs, long cropEndMs) {
|
||||||
if (uri == null) {
|
if (uri == null) {
|
||||||
throw new IllegalStateException("Invalid video uri");
|
throw new IllegalStateException("Invalid video uri");
|
||||||
}
|
}
|
||||||
@ -822,12 +828,12 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
)
|
)
|
||||||
.createMediaSource(mediaItem);
|
.createMediaSource(mediaItem);
|
||||||
|
|
||||||
if (startTimeMs >= 0 && endTimeMs >= 0) {
|
if (cropStartMs >= 0 && cropEndMs >= 0) {
|
||||||
return new ClippingMediaSource(mediaSource, startTimeMs * 1000, endTimeMs * 1000);
|
return new ClippingMediaSource(mediaSource, cropStartMs * 1000, cropEndMs * 1000);
|
||||||
} else if (startTimeMs >= 0) {
|
} else if (cropStartMs >= 0) {
|
||||||
return new ClippingMediaSource(mediaSource, startTimeMs * 1000, TIME_END_OF_SOURCE);
|
return new ClippingMediaSource(mediaSource, cropStartMs * 1000, TIME_END_OF_SOURCE);
|
||||||
} else if (endTimeMs >= 0) {
|
} else if (cropEndMs >= 0) {
|
||||||
return new ClippingMediaSource(mediaSource, 0, endTimeMs * 1000);
|
return new ClippingMediaSource(mediaSource, 0, cropEndMs * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mediaSource;
|
return mediaSource;
|
||||||
@ -1500,13 +1506,14 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
|
|
||||||
// ReactExoplayerViewManager public api
|
// ReactExoplayerViewManager public api
|
||||||
|
|
||||||
public void setSrc(final Uri uri, final long startTimeMs, final long endTimeMs, final String extension, Map<String, String> headers) {
|
public void setSrc(final Uri uri, final long startPositionMs, final long cropStartMs, final long cropEndMs, final String extension, Map<String, String> headers) {
|
||||||
if (uri != null) {
|
if (uri != null) {
|
||||||
boolean isSourceEqual = uri.equals(srcUri) && startTimeMs == this.startTimeMs && endTimeMs == this.endTimeMs;
|
boolean isSourceEqual = uri.equals(srcUri) && cropStartMs == this.cropStartMs && cropEndMs == this.cropEndMs;
|
||||||
hasDrmFailed = false;
|
hasDrmFailed = false;
|
||||||
this.srcUri = uri;
|
this.srcUri = uri;
|
||||||
this.startTimeMs = startTimeMs;
|
this.startPositionMs = startPositionMs;
|
||||||
this.endTimeMs = endTimeMs;
|
this.cropStartMs = cropStartMs;
|
||||||
|
this.cropEndMs = cropEndMs;
|
||||||
this.extension = extension;
|
this.extension = extension;
|
||||||
this.requestHeaders = headers;
|
this.requestHeaders = headers;
|
||||||
this.mediaDataSourceFactory =
|
this.mediaDataSourceFactory =
|
||||||
@ -1524,8 +1531,9 @@ public class ReactExoplayerView extends FrameLayout implements
|
|||||||
player.stop();
|
player.stop();
|
||||||
player.clearMediaItems();
|
player.clearMediaItems();
|
||||||
this.srcUri = null;
|
this.srcUri = null;
|
||||||
this.startTimeMs = -1;
|
this.startPositionMs = -1;
|
||||||
this.endTimeMs = -1;
|
this.cropStartMs = -1;
|
||||||
|
this.cropEndMs = -1;
|
||||||
this.extension = null;
|
this.extension = null;
|
||||||
this.requestHeaders = null;
|
this.requestHeaders = null;
|
||||||
this.mediaDataSourceFactory = null;
|
this.mediaDataSourceFactory = null;
|
||||||
|
@ -36,8 +36,9 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
|||||||
private static final String REACT_CLASS = "RCTVideo";
|
private static final String REACT_CLASS = "RCTVideo";
|
||||||
private static final String PROP_SRC = "src";
|
private static final String PROP_SRC = "src";
|
||||||
private static final String PROP_SRC_URI = "uri";
|
private static final String PROP_SRC_URI = "uri";
|
||||||
private static final String PROP_SRC_START_TIME = "startTime";
|
private static final String PROP_SRC_START_POSITION = "startPosition";
|
||||||
private static final String PROP_SRC_END_TIME = "endTime";
|
private static final String PROP_SRC_CROP_START = "cropStart";
|
||||||
|
private static final String PROP_SRC_CROP_END = "cropEnd";
|
||||||
private static final String PROP_AD_TAG_URL = "adTagUrl";
|
private static final String PROP_AD_TAG_URL = "adTagUrl";
|
||||||
private static final String PROP_SRC_TYPE = "type";
|
private static final String PROP_SRC_TYPE = "type";
|
||||||
private static final String PROP_DRM = "drm";
|
private static final String PROP_DRM = "drm";
|
||||||
@ -75,6 +76,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
|||||||
private static final String PROP_MIN_LOAD_RETRY_COUNT = "minLoadRetryCount";
|
private static final String PROP_MIN_LOAD_RETRY_COUNT = "minLoadRetryCount";
|
||||||
private static final String PROP_MAXIMUM_BIT_RATE = "maxBitRate";
|
private static final String PROP_MAXIMUM_BIT_RATE = "maxBitRate";
|
||||||
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
|
private static final String PROP_PLAY_IN_BACKGROUND = "playInBackground";
|
||||||
|
private static final String PROP_START_POSITION = "startPosition";
|
||||||
private static final String PROP_CONTENT_START_TIME = "contentStartTime";
|
private static final String PROP_CONTENT_START_TIME = "contentStartTime";
|
||||||
private static final String PROP_DISABLE_FOCUS = "disableFocus";
|
private static final String PROP_DISABLE_FOCUS = "disableFocus";
|
||||||
private static final String PROP_DISABLE_BUFFERING = "disableBuffering";
|
private static final String PROP_DISABLE_BUFFERING = "disableBuffering";
|
||||||
@ -151,8 +153,9 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
|||||||
public void setSrc(final ReactExoplayerView videoView, @Nullable ReadableMap src) {
|
public void setSrc(final ReactExoplayerView videoView, @Nullable ReadableMap src) {
|
||||||
Context context = videoView.getContext().getApplicationContext();
|
Context context = videoView.getContext().getApplicationContext();
|
||||||
String uriString = ReactBridgeUtils.safeGetString(src, PROP_SRC_URI, null);
|
String uriString = ReactBridgeUtils.safeGetString(src, PROP_SRC_URI, null);
|
||||||
int startTimeMs = ReactBridgeUtils.safeGetInt(src, PROP_SRC_START_TIME, -1);
|
int startPositionMs = ReactBridgeUtils.safeGetInt(src, PROP_START_POSITION, -1);
|
||||||
int endTimeMs = ReactBridgeUtils.safeGetInt(src, PROP_SRC_END_TIME, -1);
|
int cropStartMs = ReactBridgeUtils.safeGetInt(src, PROP_SRC_CROP_START, -1);
|
||||||
|
int cropEndMs = ReactBridgeUtils.safeGetInt(src, PROP_SRC_CROP_END, -1);
|
||||||
String extension = ReactBridgeUtils.safeGetString(src, PROP_SRC_TYPE, null);
|
String extension = ReactBridgeUtils.safeGetString(src, PROP_SRC_TYPE, null);
|
||||||
|
|
||||||
Map<String, String> headers = src.hasKey(PROP_SRC_HEADERS) ? ReactBridgeUtils.toStringMap(src.getMap(PROP_SRC_HEADERS)) : new HashMap<>();
|
Map<String, String> headers = src.hasKey(PROP_SRC_HEADERS) ? ReactBridgeUtils.toStringMap(src.getMap(PROP_SRC_HEADERS)) : new HashMap<>();
|
||||||
@ -166,7 +169,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
|||||||
Uri srcUri = Uri.parse(uriString);
|
Uri srcUri = Uri.parse(uriString);
|
||||||
|
|
||||||
if (srcUri != null) {
|
if (srcUri != null) {
|
||||||
videoView.setSrc(srcUri, startTimeMs, endTimeMs, extension, headers);
|
videoView.setSrc(srcUri, startPositionMs, cropStartMs, cropEndMs, extension, headers);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int identifier = context.getResources().getIdentifier(
|
int identifier = context.getResources().getIdentifier(
|
||||||
|
@ -160,10 +160,12 @@ Note on iOS, controls are always shown when in fullscreen mode.
|
|||||||
Note on Android, native controls are available by default.
|
Note on Android, native controls are available by default.
|
||||||
If needed, you can also add your controls or use a package like [react-native-video-controls](https://github.com/itsnubix/react-native-video-controls) or [react-native-media-console](https://github.com/criszz77/react-native-media-console), see [Useful Side Project](/projects).
|
If needed, you can also add your controls or use a package like [react-native-video-controls](https://github.com/itsnubix/react-native-video-controls) or [react-native-media-console](https://github.com/criszz77/react-native-media-console), see [Useful Side Project](/projects).
|
||||||
|
|
||||||
|
Platforms: Android, iOS
|
||||||
|
|
||||||
### `contentStartTime`
|
### `contentStartTime`
|
||||||
The start time in ms for SSAI content. This determines at what time to load the video info like resolutions. Use this only when you have SSAI stream where ads resolution is not the same as content resolution.
|
The start time in ms for SSAI content. This determines at what time to load the video info like resolutions. Use this only when you have SSAI stream where ads resolution is not the same as content resolution.
|
||||||
|
|
||||||
Platforms: Android, iOS
|
Platforms: Android
|
||||||
|
|
||||||
### `debug`
|
### `debug`
|
||||||
|
|
||||||
@ -656,18 +658,24 @@ type: 'mpd' }}
|
|||||||
The following other types are supported on some platforms, but aren't fully documented yet:
|
The following other types are supported on some platforms, but aren't fully documented yet:
|
||||||
`content://, ms-appx://, ms-appdata://, assets-library://`
|
`content://, ms-appx://, ms-appdata://, assets-library://`
|
||||||
|
|
||||||
|
#### Start playback at a specific point in time
|
||||||
|
|
||||||
|
Provide an optional `startPosition` for video. Value is in milliseconds. If the `cropStart` prop is applied, it will be applied from that point forward.
|
||||||
|
(If it is negative or undefined or null, it is ignored)
|
||||||
|
|
||||||
|
Platforms: Android, iOS
|
||||||
|
|
||||||
#### Playing only a portion of the video (start & end time)
|
#### Playing only a portion of the video (start & end time)
|
||||||
|
|
||||||
Provide an optional `startTime` and/or `endTime` for the video. Value is in milliseconds. Useful when you want to play only a portion of a large video.
|
Provide an optional `cropStart` and/or `cropEnd` for the video. Value is in milliseconds. Useful when you want to play only a portion of a large video.
|
||||||
|
|
||||||
Example
|
Example
|
||||||
```javascript
|
```javascript
|
||||||
source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', startTime: 36012, endTime: 48500 }}
|
source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', cropStart: 36012, cropEnd: 48500 }}
|
||||||
|
|
||||||
source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', startTime: 36012 }}
|
source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', cropStart: 36012 }}
|
||||||
|
|
||||||
source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', endTime: 48500 }}
|
source={{ uri: 'https://bitdash-a.akamaihd.net/content/sintel/hls/playlist.m3u8', cropEnd: 48500 }}
|
||||||
```
|
```
|
||||||
|
|
||||||
Platforms: iOS, Android
|
Platforms: iOS, Android
|
||||||
|
@ -6,8 +6,9 @@ struct VideoSource {
|
|||||||
let isAsset: Bool
|
let isAsset: Bool
|
||||||
let shouldCache: Bool
|
let shouldCache: Bool
|
||||||
let requestHeaders: Dictionary<String,Any>?
|
let requestHeaders: Dictionary<String,Any>?
|
||||||
let startTime: Int64?
|
let startPosition: Int64?
|
||||||
let endTime: Int64?
|
let cropStart: Int64?
|
||||||
|
let cropEnd: Int64?
|
||||||
// Custom Metadata
|
// Custom Metadata
|
||||||
let title: String?
|
let title: String?
|
||||||
let subtitle: String?
|
let subtitle: String?
|
||||||
@ -25,8 +26,9 @@ struct VideoSource {
|
|||||||
self.isAsset = false
|
self.isAsset = false
|
||||||
self.shouldCache = false
|
self.shouldCache = false
|
||||||
self.requestHeaders = nil
|
self.requestHeaders = nil
|
||||||
self.startTime = nil
|
self.startPosition = nil
|
||||||
self.endTime = nil
|
self.cropStart = nil
|
||||||
|
self.cropEnd = nil
|
||||||
self.title = nil
|
self.title = nil
|
||||||
self.subtitle = nil
|
self.subtitle = nil
|
||||||
self.description = nil
|
self.description = nil
|
||||||
@ -40,8 +42,9 @@ struct VideoSource {
|
|||||||
self.isAsset = json["isAsset"] as? Bool ?? false
|
self.isAsset = json["isAsset"] as? Bool ?? false
|
||||||
self.shouldCache = json["shouldCache"] as? Bool ?? false
|
self.shouldCache = json["shouldCache"] as? Bool ?? false
|
||||||
self.requestHeaders = json["requestHeaders"] as? Dictionary<String,Any>
|
self.requestHeaders = json["requestHeaders"] as? Dictionary<String,Any>
|
||||||
self.startTime = json["startTime"] as? Int64
|
self.startPosition = json["startPosition"] as? Int64
|
||||||
self.endTime = json["endTime"] as? Int64
|
self.cropStart = json["cropStart"] as? Int64
|
||||||
|
self.cropEnd = json["cropEnd"] as? Int64
|
||||||
self.title = json["title"] as? String
|
self.title = json["title"] as? String
|
||||||
self.subtitle = json["subtitle"] as? String
|
self.subtitle = json["subtitle"] as? String
|
||||||
self.description = json["description"] as? String
|
self.description = json["description"] as? String
|
||||||
|
@ -19,8 +19,8 @@ enum RCTVideoUtils {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if (source?.startTime != nil && source?.endTime != nil) {
|
if (source?.cropStart != nil && source?.cropEnd != nil) {
|
||||||
return NSNumber(value: (Float64(source?.endTime ?? 0) - Float64(source?.startTime ?? 0)) / 1000)
|
return NSNumber(value: (Float64(source?.cropEnd ?? 0) - Float64(source?.cropStart ?? 0)) / 1000)
|
||||||
}
|
}
|
||||||
|
|
||||||
var effectiveTimeRange:CMTimeRange?
|
var effectiveTimeRange:CMTimeRange?
|
||||||
@ -35,8 +35,8 @@ enum RCTVideoUtils {
|
|||||||
if let effectiveTimeRange = effectiveTimeRange {
|
if let effectiveTimeRange = effectiveTimeRange {
|
||||||
let playableDuration:Float64 = CMTimeGetSeconds(CMTimeRangeGetEnd(effectiveTimeRange))
|
let playableDuration:Float64 = CMTimeGetSeconds(CMTimeRangeGetEnd(effectiveTimeRange))
|
||||||
if playableDuration > 0 {
|
if playableDuration > 0 {
|
||||||
if (source?.startTime != nil) {
|
if (source?.cropStart != nil) {
|
||||||
return NSNumber(value: (playableDuration - Float64(source?.startTime ?? 0) / 1000))
|
return NSNumber(value: (playableDuration - Float64(source?.cropStart ?? 0) / 1000))
|
||||||
}
|
}
|
||||||
|
|
||||||
return playableDuration as NSNumber
|
return playableDuration as NSNumber
|
||||||
|
@ -66,6 +66,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
private var _filterEnabled:Bool = false
|
private var _filterEnabled:Bool = false
|
||||||
private var _presentingViewController:UIViewController?
|
private var _presentingViewController:UIViewController?
|
||||||
private var _pictureInPictureEnabled = false
|
private var _pictureInPictureEnabled = false
|
||||||
|
private var _startPosition:Float64 = -1
|
||||||
|
|
||||||
/* IMA Ads */
|
/* IMA Ads */
|
||||||
private var _adTagUrl:String?
|
private var _adTagUrl:String?
|
||||||
@ -251,8 +252,8 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
}
|
}
|
||||||
|
|
||||||
var currentTime = _player?.currentTime()
|
var currentTime = _player?.currentTime()
|
||||||
if (currentTime != nil && _source?.startTime != nil) {
|
if (currentTime != nil && _source?.cropStart != nil) {
|
||||||
currentTime = CMTimeSubtract(currentTime!, CMTimeMake(value: _source?.startTime ?? 0, timescale: 1000))
|
currentTime = CMTimeSubtract(currentTime!, CMTimeMake(value: _source?.cropStart ?? 0, timescale: 1000))
|
||||||
}
|
}
|
||||||
let currentPlaybackTime = _player?.currentItem?.currentDate()
|
let currentPlaybackTime = _player?.currentItem?.currentDate()
|
||||||
let duration = CMTimeGetSeconds(playerDuration)
|
let duration = CMTimeGetSeconds(playerDuration)
|
||||||
@ -316,6 +317,10 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
throw NSError(domain: "", code: 0, userInfo: nil)
|
throw NSError(domain: "", code: 0, userInfo: nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let startPosition = self._source?.startPosition {
|
||||||
|
self._startPosition = Float64(startPosition) / 1000
|
||||||
|
}
|
||||||
|
|
||||||
#if USE_VIDEO_CACHING
|
#if USE_VIDEO_CACHING
|
||||||
if self._videoCache.shouldCache(source:source, textTracks:self._textTracks) {
|
if self._videoCache.shouldCache(source:source, textTracks:self._textTracks) {
|
||||||
return self._videoCache.playerItemForSourceUsingCache(uri: source.uri, assetOptions:assetOptions)
|
return self._videoCache.playerItemForSourceUsingCache(uri: source.uri, assetOptions:assetOptions)
|
||||||
@ -341,7 +346,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
self._playerItem = playerItem
|
self._playerItem = playerItem
|
||||||
self._playerObserver.playerItem = self._playerItem
|
self._playerObserver.playerItem = self._playerItem
|
||||||
self.setPreferredForwardBufferDuration(self._preferredForwardBufferDuration)
|
self.setPreferredForwardBufferDuration(self._preferredForwardBufferDuration)
|
||||||
self.setPlaybackRange(playerItem, withVideoStart: self._source?.startTime, withVideoEnd: self._source?.endTime)
|
self.setPlaybackRange(playerItem, withVideoStart: self._source?.cropStart, withVideoEnd: self._source?.cropEnd)
|
||||||
self.setFilter(self._filterName)
|
self.setFilter(self._filterName)
|
||||||
if let maxBitRate = self._maxBitRate {
|
if let maxBitRate = self._maxBitRate {
|
||||||
self._playerItem?.preferredPeakBitRate = Double(maxBitRate)
|
self._playerItem?.preferredPeakBitRate = Double(maxBitRate)
|
||||||
@ -601,6 +606,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
_pendingSeek = false
|
_pendingSeek = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@objc
|
@objc
|
||||||
func setRate(_ rate:Float) {
|
func setRate(_ rate:Float) {
|
||||||
_rate = rate
|
_rate = rate
|
||||||
@ -1177,6 +1183,14 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
|||||||
_pendingSeek = false
|
_pendingSeek = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if _startPosition >= 0 {
|
||||||
|
setSeek([
|
||||||
|
"time": NSNumber(value: _startPosition),
|
||||||
|
"tolerance": NSNumber(value: 100)
|
||||||
|
])
|
||||||
|
_startPosition = -1
|
||||||
|
}
|
||||||
|
|
||||||
if _videoLoadStarted {
|
if _videoLoadStarted {
|
||||||
let audioTracks = RCTVideoUtils.getAudioTrackInfo(_player)
|
let audioTracks = RCTVideoUtils.getAudioTrackInfo(_player)
|
||||||
let textTracks = RCTVideoUtils.getTextTrackInfo(_player).map(\.json)
|
let textTracks = RCTVideoUtils.getTextTrackInfo(_player).map(\.json)
|
||||||
|
@ -147,9 +147,10 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
|||||||
type: resolvedSource.type || '',
|
type: resolvedSource.type || '',
|
||||||
mainVer: resolvedSource.mainVer || 0,
|
mainVer: resolvedSource.mainVer || 0,
|
||||||
patchVer: resolvedSource.patchVer || 0,
|
patchVer: resolvedSource.patchVer || 0,
|
||||||
requestHeaders: resolvedSource?.headers || {},
|
requestHeaders: resolvedSource.headers || {},
|
||||||
startTime: resolvedSource.startTime || 0,
|
startPosition: resolvedSource.startPosition ?? -1,
|
||||||
endTime: resolvedSource.endTime,
|
cropStart: resolvedSource.cropStart || 0,
|
||||||
|
cropEnd: resolvedSource.cropEnd,
|
||||||
title: resolvedSource.title,
|
title: resolvedSource.title,
|
||||||
subtitle: resolvedSource.subtitle,
|
subtitle: resolvedSource.subtitle,
|
||||||
description: resolvedSource.description,
|
description: resolvedSource.description,
|
||||||
|
@ -23,8 +23,9 @@ type VideoSrc = Readonly<{
|
|||||||
mainVer?: number;
|
mainVer?: number;
|
||||||
patchVer?: number;
|
patchVer?: number;
|
||||||
requestHeaders?: Headers;
|
requestHeaders?: Headers;
|
||||||
startTime?: number;
|
startPosition?: number;
|
||||||
endTime?: number;
|
cropStart?: number;
|
||||||
|
cropEnd?: number;
|
||||||
title?: string;
|
title?: string;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
@ -15,8 +15,9 @@ export type ReactVideoSourceProperties = {
|
|||||||
mainVer?: number;
|
mainVer?: number;
|
||||||
patchVer?: number;
|
patchVer?: number;
|
||||||
headers?: Headers;
|
headers?: Headers;
|
||||||
startTime?: number;
|
startPosition?: number;
|
||||||
endTime?: number;
|
cropStart?: number;
|
||||||
|
cropEnd?: number;
|
||||||
title?: string;
|
title?: string;
|
||||||
subtitle?: string;
|
subtitle?: string;
|
||||||
description?: string;
|
description?: string;
|
||||||
|
Loading…
Reference in New Issue
Block a user