react-native-video/Video.js

539 lines
16 KiB
JavaScript
Raw Normal View History

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { StyleSheet, requireNativeComponent, NativeModules, View, ViewPropTypes, Image, Platform, findNodeHandle } from 'react-native';
2016-06-22 07:52:12 -06:00
import resolveAssetSource from 'react-native/Libraries/Image/resolveAssetSource';
import TextTrackType from './TextTrackType';
import FilterType from './FilterType';
Add iOS and Android basic DRM support (#1445) This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey) I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR. **Test stream for ANDROID:** ``` testStream = { uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)', type: 'mpd', drm: { type: DRMType.PLAYREADY, licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)' } }; ``` or ``` { uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd', drm: { type: 'widevine', //or DRMType.WIDEVINE licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense', headers: { 'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU' }, } } ``` **Test stream for iOS:** Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them. It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
import DRMType from './DRMType';
import VideoResizeMode from './VideoResizeMode.js';
const styles = StyleSheet.create({
base: {
overflow: 'hidden',
},
});
Add iOS and Android basic DRM support (#1445) This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey) I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR. **Test stream for ANDROID:** ``` testStream = { uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)', type: 'mpd', drm: { type: DRMType.PLAYREADY, licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)' } }; ``` or ``` { uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd', drm: { type: 'widevine', //or DRMType.WIDEVINE licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense', headers: { 'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU' }, } } ``` **Test stream for iOS:** Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them. It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
export { TextTrackType, FilterType, DRMType };
export default class Video extends Component {
constructor(props) {
super(props);
this.state = {
showPoster: !!props.poster,
};
}
2015-11-09 18:55:39 -07:00
setNativeProps(nativeProps) {
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;
}
2015-11-09 18:55:39 -07:00
seek = (time, tolerance = 100) => {
if (isNaN(time)) {throw new Error('Specified time is not a number');}
if (Platform.OS === 'ios') {
this.setNativeProps({
seek: {
time,
tolerance,
},
});
} else {
this.setNativeProps({ seek: time });
}
2016-06-22 08:28:54 -06:00
};
2016-06-22 08:28:54 -06:00
presentFullscreenPlayer = () => {
this.setNativeProps({ fullscreen: true });
2016-06-22 08:28:54 -06:00
};
2016-06-22 08:28:54 -06:00
dismissFullscreenPlayer = () => {
this.setNativeProps({ fullscreen: false });
2016-06-22 08:28:54 -06:00
};
save = async (options?) => {
2018-10-26 07:21:41 -06:00
return await NativeModules.VideoManager.save(options, findNodeHandle(this._root));
}
restoreUserInterfaceForPictureInPictureStopCompleted = (restored) => {
this.setNativeProps({ restoreUserInterfaceForPIPStopCompletionHandler: restored });
};
2016-06-22 08:28:54 -06:00
_assignRoot = (component) => {
this._root = component;
2016-06-22 08:28:54 -06:00
};
_hidePoster = () => {
if (this.state.showPoster) {
this.setState({ showPoster: false });
}
}
2016-06-22 08:28:54 -06:00
_onLoadStart = (event) => {
if (this.props.onLoadStart) {
this.props.onLoadStart(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2015-11-17 20:15:07 -07:00
_onPlaybackStateChanged = (event) => {
if (this.props.onPlaybackStateChanged) {
this.props.onPlaybackStateChanged(event.nativeEvent);
}
};
2016-06-22 08:28:54 -06:00
_onLoad = (event) => {
// Need to hide poster here for windows as onReadyForDisplay is not implemented
if (Platform.OS === 'windows') {
this._hidePoster();
}
if (this.props.onLoad) {
this.props.onLoad(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2015-11-17 20:15:07 -07:00
2016-06-22 08:28:54 -06:00
_onError = (event) => {
if (this.props.onError) {
this.props.onError(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2015-11-17 20:15:07 -07:00
2016-06-22 08:28:54 -06:00
_onProgress = (event) => {
if (this.props.onProgress) {
this.props.onProgress(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2015-11-17 20:15:07 -07:00
_onBandwidthUpdate = (event) => {
if (this.props.onBandwidthUpdate) {
this.props.onBandwidthUpdate(event.nativeEvent);
}
};
2016-06-22 08:28:54 -06:00
_onSeek = (event) => {
if (this.props.onSeek) {
this.props.onSeek(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2015-11-17 20:15:07 -07:00
2016-06-22 08:28:54 -06:00
_onEnd = (event) => {
if (this.props.onEnd) {
this.props.onEnd(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2015-11-17 20:15:07 -07:00
_onTimedMetadata = (event) => {
if (this.props.onTimedMetadata) {
this.props.onTimedMetadata(event.nativeEvent);
}
};
2016-06-22 08:28:54 -06:00
_onFullscreenPlayerWillPresent = (event) => {
if (this.props.onFullscreenPlayerWillPresent) {
this.props.onFullscreenPlayerWillPresent(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2016-06-22 08:28:54 -06:00
_onFullscreenPlayerDidPresent = (event) => {
2016-03-31 13:40:49 -06:00
if (this.props.onFullscreenPlayerDidPresent) {
this.props.onFullscreenPlayerDidPresent(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2016-06-22 08:28:54 -06:00
_onFullscreenPlayerWillDismiss = (event) => {
2016-03-31 13:40:49 -06:00
if (this.props.onFullscreenPlayerWillDismiss) {
this.props.onFullscreenPlayerWillDismiss(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2016-06-22 08:28:54 -06:00
_onFullscreenPlayerDidDismiss = (event) => {
if (this.props.onFullscreenPlayerDidDismiss) {
this.props.onFullscreenPlayerDidDismiss(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2015-11-17 20:15:07 -07:00
2016-06-22 08:28:54 -06:00
_onReadyForDisplay = (event) => {
2019-11-26 12:40:03 -07:00
if (!this.props.audioOnly) {
this._hidePoster();
}
2016-04-28 06:42:44 -06:00
if (this.props.onReadyForDisplay) {
this.props.onReadyForDisplay(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2016-04-28 06:42:44 -06:00
2016-06-22 08:28:54 -06:00
_onPlaybackStalled = (event) => {
2016-04-28 06:42:44 -06:00
if (this.props.onPlaybackStalled) {
this.props.onPlaybackStalled(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2016-04-28 06:42:44 -06:00
2016-06-22 08:28:54 -06:00
_onPlaybackResume = (event) => {
2016-04-28 06:42:44 -06:00
if (this.props.onPlaybackResume) {
this.props.onPlaybackResume(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
2016-04-28 06:42:44 -06:00
2016-06-22 08:28:54 -06:00
_onPlaybackRateChange = (event) => {
2016-04-28 06:42:44 -06:00
if (this.props.onPlaybackRateChange) {
this.props.onPlaybackRateChange(event.nativeEvent);
}
2016-06-22 08:28:54 -06:00
};
_onExternalPlaybackChange = (event) => {
if (this.props.onExternalPlaybackChange) {
this.props.onExternalPlaybackChange(event.nativeEvent);
}
}
2016-04-28 06:42:44 -06:00
2017-01-11 05:51:45 -07:00
_onAudioBecomingNoisy = () => {
if (this.props.onAudioBecomingNoisy) {
this.props.onAudioBecomingNoisy();
}
};
_onPictureInPictureStatusChanged = (event) => {
if (this.props.onPictureInPictureStatusChanged) {
this.props.onPictureInPictureStatusChanged(event.nativeEvent);
}
};
_onRestoreUserInterfaceForPictureInPictureStop = (event) => {
if (this.props.onRestoreUserInterfaceForPictureInPictureStop) {
this.props.onRestoreUserInterfaceForPictureInPictureStop();
}
};
2017-01-11 05:51:45 -07:00
_onAudioFocusChanged = (event) => {
if (this.props.onAudioFocusChanged) {
this.props.onAudioFocusChanged(event.nativeEvent);
}
};
_onBuffer = (event) => {
if (this.props.onBuffer) {
this.props.onBuffer(event.nativeEvent);
}
};
_onBufferProgress = (event) => {
if (this.props.onBufferProgress) {
this.props.onBufferProgress(event.nativeEvent);
}
};
Add iOS and Android basic DRM support (#1445) This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey) I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR. **Test stream for ANDROID:** ``` testStream = { uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)', type: 'mpd', drm: { type: DRMType.PLAYREADY, licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)' } }; ``` or ``` { uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd', drm: { type: 'widevine', //or DRMType.WIDEVINE licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense', headers: { 'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU' }, } } ``` **Test stream for iOS:** Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them. It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
_onGetLicense = (event) => {
if (this.props.drm && this.props.drm.getLicense instanceof Function) {
const data = event.nativeEvent;
if (data && data.spcBase64) {
const getLicenseOverride = this.props.drm.getLicense(data.spcBase64, data.contentId, data.licenseUrl);
Add iOS and Android basic DRM support (#1445) This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey) I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR. **Test stream for ANDROID:** ``` testStream = { uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)', type: 'mpd', drm: { type: DRMType.PLAYREADY, licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)' } }; ``` or ``` { uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd', drm: { type: 'widevine', //or DRMType.WIDEVINE licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense', headers: { 'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU' }, } } ``` **Test stream for iOS:** Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them. It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
const getLicensePromise = Promise.resolve(getLicenseOverride); // Handles both scenarios, getLicenseOverride being a promise and not.
getLicensePromise.then((result => {
if (result !== undefined) {
NativeModules.VideoManager.setLicenseResult(result, findNodeHandle(this._root));
} else {
NativeModules.VideoManager.setLicenseError && NativeModules.VideoManager.setLicenseError('Empty license result', findNodeHandle(this._root));
}
})).catch((error) => {
NativeModules.VideoManager.setLicenseError && NativeModules.VideoManager.setLicenseError(error, findNodeHandle(this._root));
});
} else {
NativeModules.VideoManager.setLicenseError && NativeModules.VideoManager.setLicenseError("No spc received", findNodeHandle(this._root));
}
}
}
getViewManagerConfig = viewManagerName => {
2019-02-18 23:38:09 -07:00
if (!NativeModules.UIManager.getViewManagerConfig) {
return NativeModules.UIManager[viewManagerName];
}
2019-02-18 23:38:09 -07:00
return NativeModules.UIManager.getViewManagerConfig(viewManagerName);
};
render() {
2016-06-22 07:52:12 -06:00
const resizeMode = this.props.resizeMode;
const source = resolveAssetSource(this.props.source) || {};
const shouldCache = !source.__packager_asset;
let uri = source.uri || '';
if (uri && uri.match(/^\//)) {
uri = `file://${uri}`;
}
if (!uri) {
console.warn('Trying to load empty source.');
}
const isNetwork = !!(uri && uri.match(/^https?:/));
2018-01-31 05:23:19 -07:00
const isAsset = !!(uri && uri.match(/^(assets-library|ipod-library|file|content|ms-appx|ms-appdata):/));
let nativeResizeMode;
const RCTVideoInstance = this.getViewManagerConfig('RCTVideo');
if (resizeMode === VideoResizeMode.stretch) {
nativeResizeMode = RCTVideoInstance.Constants.ScaleToFill;
} else if (resizeMode === VideoResizeMode.contain) {
nativeResizeMode = RCTVideoInstance.Constants.ScaleAspectFit;
} else if (resizeMode === VideoResizeMode.cover) {
nativeResizeMode = RCTVideoInstance.Constants.ScaleAspectFill;
} else {
nativeResizeMode = RCTVideoInstance.Constants.ScaleNone;
}
const nativeProps = Object.assign({}, this.props);
Object.assign(nativeProps, {
style: [styles.base, nativeProps.style],
resizeMode: nativeResizeMode,
src: {
uri,
isNetwork,
isAsset,
shouldCache,
type: source.type || '',
mainVer: source.mainVer || 0,
patchVer: source.patchVer || 0,
requestHeaders: source.headers ? this.stringsOnlyObject(source.headers) : {},
},
onVideoLoadStart: this._onLoadStart,
onVideoPlaybackStateChanged: this._onPlaybackStateChanged,
onVideoLoad: this._onLoad,
onVideoError: this._onError,
onVideoProgress: this._onProgress,
onVideoSeek: this._onSeek,
onVideoEnd: this._onEnd,
2017-01-11 05:51:45 -07:00
onVideoBuffer: this._onBuffer,
onVideoBufferProgress: this._onBufferProgress,
2018-11-01 10:11:57 -06:00
onVideoBandwidthUpdate: this._onBandwidthUpdate,
onTimedMetadata: this._onTimedMetadata,
2018-07-12 22:48:58 -06:00
onVideoAudioBecomingNoisy: this._onAudioBecomingNoisy,
onVideoExternalPlaybackChange: this._onExternalPlaybackChange,
onVideoFullscreenPlayerWillPresent: this._onFullscreenPlayerWillPresent,
onVideoFullscreenPlayerDidPresent: this._onFullscreenPlayerDidPresent,
onVideoFullscreenPlayerWillDismiss: this._onFullscreenPlayerWillDismiss,
onVideoFullscreenPlayerDidDismiss: this._onFullscreenPlayerDidDismiss,
2016-04-28 06:42:44 -06:00
onReadyForDisplay: this._onReadyForDisplay,
onPlaybackStalled: this._onPlaybackStalled,
onPlaybackResume: this._onPlaybackResume,
onPlaybackRateChange: this._onPlaybackRateChange,
2017-01-11 05:51:45 -07:00
onAudioFocusChanged: this._onAudioFocusChanged,
onAudioBecomingNoisy: this._onAudioBecomingNoisy,
Add iOS and Android basic DRM support (#1445) This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey) I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR. **Test stream for ANDROID:** ``` testStream = { uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)', type: 'mpd', drm: { type: DRMType.PLAYREADY, licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)' } }; ``` or ``` { uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd', drm: { type: 'widevine', //or DRMType.WIDEVINE licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense', headers: { 'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU' }, } } ``` **Test stream for iOS:** Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them. It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
onGetLicense: nativeProps.drm && nativeProps.drm.getLicense && this._onGetLicense,
onPictureInPictureStatusChanged: this._onPictureInPictureStatusChanged,
onRestoreUserInterfaceForPictureInPictureStop: this._onRestoreUserInterfaceForPictureInPictureStop,
});
const posterStyle = {
...StyleSheet.absoluteFillObject,
resizeMode: this.props.posterResizeMode || 'contain',
};
2015-11-09 18:55:39 -07:00
return (
<View style={nativeProps.style}>
<RCTVideo
ref={this._assignRoot}
{...nativeProps}
style={StyleSheet.absoluteFill}
/>
{this.state.showPoster && (
<Image style={posterStyle} source={{ uri: this.props.poster }} />
)}
</View>
2015-11-09 18:55:39 -07:00
);
}
}
Video.propTypes = {
filter: PropTypes.oneOf([
FilterType.NONE,
FilterType.INVERT,
FilterType.MONOCHROME,
FilterType.POSTERIZE,
FilterType.FALSE,
FilterType.MAXIMUMCOMPONENT,
FilterType.MINIMUMCOMPONENT,
FilterType.CHROME,
FilterType.FADE,
FilterType.INSTANT,
FilterType.MONO,
FilterType.NOIR,
FilterType.PROCESS,
FilterType.TONAL,
FilterType.TRANSFER,
FilterType.SEPIA,
]),
filterEnabled: PropTypes.bool,
/* Native only */
src: PropTypes.object,
seek: PropTypes.oneOfType([
PropTypes.number,
PropTypes.object,
]),
fullscreen: PropTypes.bool,
onVideoLoadStart: PropTypes.func,
onVideoLoad: PropTypes.func,
2017-01-11 05:51:45 -07:00
onVideoBuffer: PropTypes.func,
onVideoError: PropTypes.func,
onVideoProgress: PropTypes.func,
2018-11-01 10:11:57 -06:00
onVideoBandwidthUpdate: PropTypes.func,
onVideoSeek: PropTypes.func,
onVideoEnd: PropTypes.func,
onTimedMetadata: PropTypes.func,
2018-07-12 22:48:58 -06:00
onVideoAudioBecomingNoisy: PropTypes.func,
onVideoExternalPlaybackChange: PropTypes.func,
onVideoFullscreenPlayerWillPresent: PropTypes.func,
onVideoFullscreenPlayerDidPresent: PropTypes.func,
onVideoFullscreenPlayerWillDismiss: PropTypes.func,
onVideoFullscreenPlayerDidDismiss: PropTypes.func,
/* Wrapper component */
2016-06-22 07:52:12 -06:00
source: PropTypes.oneOfType([
PropTypes.shape({
uri: PropTypes.string,
2016-06-22 07:52:12 -06:00
}),
// Opaque type returned by require('./video.mp4')
PropTypes.number,
2016-06-22 07:52:12 -06:00
]),
Add iOS and Android basic DRM support (#1445) This PR adds support for DRM streams on iOS (Fairplay) and Android (Playready, Widevine, Clearkey) I am neither Android nor iOS developer, so feel free to provide feedback to improve this PR. **Test stream for ANDROID:** ``` testStream = { uri: 'http://profficialsite.origin.mediaservices.windows.net/c51358ea-9a5e-4322-8951-897d640fdfd7/tearsofsteel_4k.ism/manifest(format=mpd-time-csf)', type: 'mpd', drm: { type: DRMType.PLAYREADY, licenseServer: 'http://test.playready.microsoft.com/service/rightsmanager.asmx?cfg=(persist:false,sl:150)' } }; ``` or ``` { uri: 'https://media.axprod.net/TestVectors/v7-MultiDRM-SingleKey/Manifest_1080p.mpd', drm: { type: 'widevine', //or DRMType.WIDEVINE licenseServer: 'https://drm-widevine-licensing.axtest.net/AcquireLicense', headers: { 'X-AxDRM-Message': 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2ZXJzaW9uIjoxLCJjb21fa2V5X2lkIjoiYjMzNjRlYjUtNTFmNi00YWUzLThjOTgtMzNjZWQ1ZTMxYzc4IiwibWVzc2FnZSI6eyJ0eXBlIjoiZW50aXRsZW1lbnRfbWVzc2FnZSIsImZpcnN0X3BsYXlfZXhwaXJhdGlvbiI6NjAsInBsYXlyZWFkeSI6eyJyZWFsX3RpbWVfZXhwaXJhdGlvbiI6dHJ1ZX0sImtleXMiOlt7ImlkIjoiOWViNDA1MGQtZTQ0Yi00ODAyLTkzMmUtMjdkNzUwODNlMjY2IiwiZW5jcnlwdGVkX2tleSI6ImxLM09qSExZVzI0Y3Iya3RSNzRmbnc9PSJ9XX19.FAbIiPxX8BHi9RwfzD7Yn-wugU19ghrkBFKsaCPrZmU' }, } } ``` **Test stream for iOS:** Sorry but I can not provide free streams to test. If anyone can provide test streams, or found some we can use, please let me know to also test them. It has been tested with a private provider and they work, at least with the `getLicense` override method. (An example implementation is provided in the README)
2020-08-12 19:56:21 -06:00
drm: PropTypes.shape({
type: PropTypes.oneOf([
DRMType.CLEARKEY, DRMType.FAIRPLAY, DRMType.WIDEVINE, DRMType.PLAYREADY
]),
licenseServer: PropTypes.string,
headers: PropTypes.shape({}),
base64Certificate: PropTypes.bool,
certificateUrl: PropTypes.string,
getLicense: PropTypes.func,
}),
localSourceEncryptionKeyScheme: PropTypes.string,
minLoadRetryCount: PropTypes.number,
maxBitRate: PropTypes.number,
resizeMode: PropTypes.string,
poster: PropTypes.string,
2017-04-30 05:43:01 -06:00
posterResizeMode: Image.propTypes.resizeMode,
repeat: PropTypes.bool,
automaticallyWaitsToMinimizeStalling: PropTypes.bool,
allowsExternalPlayback: PropTypes.bool,
selectedAudioTrack: PropTypes.shape({
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
}),
selectedVideoTrack: PropTypes.shape({
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
}),
selectedTextTrack: PropTypes.shape({
type: PropTypes.string.isRequired,
value: PropTypes.oneOfType([
PropTypes.string,
PropTypes.number,
]),
}),
textTracks: PropTypes.arrayOf(
PropTypes.shape({
title: PropTypes.string,
uri: PropTypes.string.isRequired,
type: PropTypes.oneOf([
TextTrackType.SRT,
TextTrackType.TTML,
TextTrackType.VTT,
]),
language: PropTypes.string.isRequired,
})
),
paused: PropTypes.bool,
muted: PropTypes.bool,
volume: PropTypes.number,
bufferConfig: PropTypes.shape({
minBufferMs: PropTypes.number,
maxBufferMs: PropTypes.number,
bufferForPlaybackMs: PropTypes.number,
bufferForPlaybackAfterRebufferMs: PropTypes.number,
maxHeapAllocationPercent: PropTypes.number,
}),
stereoPan: PropTypes.number,
rate: PropTypes.number,
pictureInPicture: PropTypes.bool,
playInBackground: PropTypes.bool,
2020-05-15 01:25:19 -06:00
preferredForwardBufferDuration: PropTypes.number,
playWhenInactive: PropTypes.bool,
ignoreSilentSwitch: PropTypes.oneOf(['ignore', 'obey']),
reportBandwidth: PropTypes.bool,
contentStartTime: PropTypes.number,
2017-01-11 05:51:45 -07:00
disableFocus: PropTypes.bool,
disableBuffering: PropTypes.bool,
2015-12-22 16:39:04 -07:00
controls: PropTypes.bool,
2018-06-20 17:52:48 -06:00
audioOnly: PropTypes.bool,
2015-12-22 16:39:04 -07:00
currentTime: PropTypes.number,
fullscreenAutorotate: PropTypes.bool,
fullscreenOrientation: PropTypes.oneOf(['all', 'landscape', 'portrait']),
progressUpdateInterval: PropTypes.number,
useTextureView: PropTypes.bool,
useSecureView: PropTypes.bool,
hideShutterView: PropTypes.bool,
onLoadStart: PropTypes.func,
onPlaybackStateChanged: PropTypes.func,
onLoad: PropTypes.func,
2017-01-11 05:51:45 -07:00
onBuffer: PropTypes.func,
onError: PropTypes.func,
onProgress: PropTypes.func,
2018-11-01 10:11:57 -06:00
onBandwidthUpdate: PropTypes.func,
onSeek: PropTypes.func,
onEnd: PropTypes.func,
onFullscreenPlayerWillPresent: PropTypes.func,
onFullscreenPlayerDidPresent: PropTypes.func,
onFullscreenPlayerWillDismiss: PropTypes.func,
onFullscreenPlayerDidDismiss: PropTypes.func,
2016-04-28 06:42:44 -06:00
onReadyForDisplay: PropTypes.func,
onPlaybackStalled: PropTypes.func,
onPlaybackResume: PropTypes.func,
onPlaybackRateChange: PropTypes.func,
2017-01-11 05:51:45 -07:00
onAudioFocusChanged: PropTypes.func,
onAudioBecomingNoisy: PropTypes.func,
onPictureInPictureStatusChanged: PropTypes.func,
needsToRestoreUserInterfaceForPictureInPictureStop: PropTypes.func,
onExternalPlaybackChange: PropTypes.func,
/* Required by react-native */
2016-06-22 07:52:12 -06:00
scaleX: PropTypes.number,
scaleY: PropTypes.number,
translateX: PropTypes.number,
translateY: PropTypes.number,
rotation: PropTypes.number,
2017-11-03 12:38:37 -06:00
...ViewPropTypes,
};
const RCTVideo = requireNativeComponent('RCTVideo', Video, {
nativeOnly: {
src: true,
seek: true,
fullscreen: true,
},
});