Merge pull request #2740 from iFeelSmart/feature/add_api_to_retrieve_decoder_capabilities
feat(android): add an api to retrieve decoder capabilities
This commit is contained in:
commit
f4bdabf0c6
66
API.md
66
API.md
@ -345,6 +345,13 @@ var styles = StyleSheet.create({
|
|||||||
|[restoreUserInterfaceForPictureInPictureStop](#restoreuserinterfaceforpictureinpicturestop)|iOS|
|
|[restoreUserInterfaceForPictureInPictureStop](#restoreuserinterfaceforpictureinpicturestop)|iOS|
|
||||||
|[seek](#seek)|All|
|
|[seek](#seek)|All|
|
||||||
|
|
||||||
|
### Static methods
|
||||||
|
|
||||||
|
| Name |Plateforms Support |
|
||||||
|
|--|--|
|
||||||
|
|[getWidevineLevel](#getWidevineLevel)|Android|
|
||||||
|
|[isCodecSupported](#isCodecSupported)|Android|
|
||||||
|
|[isHEVCSupported](#isHEVCSupported)|Android|
|
||||||
|
|
||||||
### Configurable props
|
### Configurable props
|
||||||
|
|
||||||
@ -1351,8 +1358,67 @@ this.player.seek(120, 50); // Seek to 2 minutes with +/- 50 milliseconds accurac
|
|||||||
|
|
||||||
Platforms: iOS
|
Platforms: iOS
|
||||||
|
|
||||||
|
#### Static methods
|
||||||
|
|
||||||
|
### Video Decoding capabilities
|
||||||
|
|
||||||
|
A module embed in ReactNativeVideo allow to query device supported feature.
|
||||||
|
To use it include the module as following:
|
||||||
|
```javascript
|
||||||
|
import { VideoDecoderProperties } from '@ifs/react-native-video-enhanced'
|
||||||
|
```
|
||||||
|
|
||||||
|
Platforms: Android
|
||||||
|
|
||||||
|
#### getWidevineLevel
|
||||||
|
|
||||||
|
Indicates whether the widevine level supported by device.
|
||||||
|
|
||||||
|
Possible results:
|
||||||
|
- **0** - unable to determine widevine support (typically not supported)
|
||||||
|
- **1**, **2**, **3** - Widevine level supported
|
||||||
|
|
||||||
|
Platforms: Android
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```
|
||||||
|
VideoDecoderProperties.getWidevineLevel().then((widevineLevel) => {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### isCodecSupported
|
||||||
|
|
||||||
|
Indicates whether the provided codec is supported level supported by device.
|
||||||
|
|
||||||
|
parameters:
|
||||||
|
- **mimetype**: mime type of codec to query
|
||||||
|
- **width**, **height**: resolution to query
|
||||||
|
|
||||||
|
Possible results:
|
||||||
|
- **true** - codec supported
|
||||||
|
- **false** - codec is not supported
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
VideoDecoderProperties.isCodecSupported('video/avc', 1920, 1080).then(
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
Platforms: Android
|
||||||
|
|
||||||
|
#### isHEVCSupported
|
||||||
|
|
||||||
|
Helper which Indicates whether the provided HEVC/1920*1080 is supported level supported by device.
|
||||||
|
It uses isCodecSupported internally.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
```
|
||||||
|
VideoDecoderProperties.isHEVCSupported().then((hevcSupported) => {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### iOS App Transport Security
|
### iOS App Transport Security
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
### Version 6.0.0-alpha.2
|
### Version 6.0.0-alpha.2
|
||||||
|
|
||||||
|
- Feature add new APIs to query supported features of device decoder (widevine level & codec capabilities) on android [#2740](https://github.com/react-native-video/react-native-video/pull/2740)
|
||||||
- Feature add support of subtitle styling on android [#2759](https://github.com/react-native-video/react-native-video/pull/2759)
|
- Feature add support of subtitle styling on android [#2759](https://github.com/react-native-video/react-native-video/pull/2759)
|
||||||
- Fix Android #2690 ensure onEnd is not sent twice [#2690](https://github.com/react-native-video/react-native-video/issues/2690)
|
- Fix Android #2690 ensure onEnd is not sent twice [#2690](https://github.com/react-native-video/react-native-video/issues/2690)
|
||||||
- Fix Exoplayer progress not reported when paused [#2664](https://github.com/react-native-video/react-native-video/pull/2664)
|
- Fix Exoplayer progress not reported when paused [#2664](https://github.com/react-native-video/react-native-video/pull/2664)
|
||||||
|
3
Video.js
3
Video.js
@ -14,7 +14,8 @@ const styles = StyleSheet.create({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export { TextTrackType, FilterType, DRMType };
|
const { VideoDecoderProperties } = NativeModules
|
||||||
|
export { TextTrackType, FilterType, DRMType, VideoDecoderProperties }
|
||||||
|
|
||||||
export default class Video extends Component {
|
export default class Video extends Component {
|
||||||
|
|
||||||
|
@ -25,7 +25,9 @@ public class ReactVideoPackage implements ReactPackage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
|
||||||
return Collections.emptyList();
|
return Collections.singletonList(
|
||||||
|
new VideoDecoderPropertiesModule(reactContext)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Deprecated RN 0.47
|
// Deprecated RN 0.47
|
||||||
|
@ -0,0 +1,107 @@
|
|||||||
|
package com.brentvatne.react;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
|
import android.media.MediaCodecList;
|
||||||
|
import android.media.MediaDrm;
|
||||||
|
import android.media.MediaFormat;
|
||||||
|
import android.media.UnsupportedSchemeException;
|
||||||
|
import android.os.Build;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.annotation.RequiresApi;
|
||||||
|
|
||||||
|
import com.facebook.react.bridge.Promise;
|
||||||
|
import com.facebook.react.bridge.ReactApplicationContext;
|
||||||
|
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||||
|
import com.facebook.react.bridge.ReactMethod;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR2)
|
||||||
|
public class VideoDecoderPropertiesModule extends ReactContextBaseJavaModule {
|
||||||
|
|
||||||
|
ReactApplicationContext reactContext;
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "VideoDecoderProperties";
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ObsoleteSdkInt")
|
||||||
|
@ReactMethod
|
||||||
|
public void getWidevineLevel(Promise p) {
|
||||||
|
int widevineLevel = 0;
|
||||||
|
|
||||||
|
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR2) {
|
||||||
|
p.resolve(widevineLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final UUID WIDEVINE_UUID = new UUID(0xEDEF8BA979D64ACEL, 0xA3C827DCD51D21EDL);
|
||||||
|
final String WIDEVINE_SECURITY_LEVEL_1 = "L1";
|
||||||
|
final String WIDEVINE_SECURITY_LEVEL_2 = "L2";
|
||||||
|
final String WIDEVINE_SECURITY_LEVEL_3 = "L3";
|
||||||
|
final String SECURITY_LEVEL_PROPERTY = "securityLevel";
|
||||||
|
|
||||||
|
String securityProperty = null;
|
||||||
|
try {
|
||||||
|
MediaDrm mediaDrm = new MediaDrm(WIDEVINE_UUID);
|
||||||
|
securityProperty = mediaDrm.getPropertyString(SECURITY_LEVEL_PROPERTY);
|
||||||
|
} catch (UnsupportedSchemeException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
if (securityProperty == null) {
|
||||||
|
p.resolve(widevineLevel);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (securityProperty) {
|
||||||
|
case WIDEVINE_SECURITY_LEVEL_1: {
|
||||||
|
widevineLevel = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WIDEVINE_SECURITY_LEVEL_2: {
|
||||||
|
widevineLevel = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case WIDEVINE_SECURITY_LEVEL_3: {
|
||||||
|
widevineLevel = 3;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
// widevineLevel 0
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
p.resolve(widevineLevel);
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ObsoleteSdkInt")
|
||||||
|
@ReactMethod
|
||||||
|
public void isCodecSupported(String mimeType, int width, int height, Promise p) {
|
||||||
|
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
p.resolve(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
MediaCodecList mRegularCodecs = new MediaCodecList(MediaCodecList.REGULAR_CODECS);
|
||||||
|
MediaFormat format = MediaFormat.createVideoFormat(mimeType, width, height);
|
||||||
|
String codecName = mRegularCodecs.findDecoderForFormat(format);
|
||||||
|
if (codecName == null) {
|
||||||
|
p.resolve(false);
|
||||||
|
} else {
|
||||||
|
p.resolve(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ReactMethod
|
||||||
|
public void isHEVCSupported(Promise p) {
|
||||||
|
isCodecSupported("video/hevc", 1920, 1080, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
public VideoDecoderPropertiesModule(ReactApplicationContext reactContext) {
|
||||||
|
super(reactContext);
|
||||||
|
this.reactContext = reactContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -16,7 +16,7 @@ import {
|
|||||||
|
|
||||||
import { Picker } from '@react-native-picker/picker'
|
import { Picker } from '@react-native-picker/picker'
|
||||||
|
|
||||||
import Video, { TextTrackType } from 'react-native-video';
|
import Video, { VideoDecoderProperties, TextTrackType } from 'react-native-video';
|
||||||
|
|
||||||
class VideoPlayer extends Component {
|
class VideoPlayer extends Component {
|
||||||
|
|
||||||
@ -77,6 +77,28 @@ class VideoPlayer extends Component {
|
|||||||
video: Video;
|
video: Video;
|
||||||
seekPanResponder: PanResponder | undefined;
|
seekPanResponder: PanResponder | undefined;
|
||||||
|
|
||||||
|
popupInfo = () => {
|
||||||
|
VideoDecoderProperties.getWidevineLevel().then((widevineLevel: number) => {
|
||||||
|
VideoDecoderProperties.isHEVCSupported().then((hevcSupported: boolean) => {
|
||||||
|
VideoDecoderProperties.isCodecSupported('video/avc', 1920, 1080).then(
|
||||||
|
(avcSupported: boolean) => {
|
||||||
|
this.toast(
|
||||||
|
true,
|
||||||
|
'Widevine level: ' +
|
||||||
|
widevineLevel +
|
||||||
|
'\n hevc: ' +
|
||||||
|
(hevcSupported ? '' : 'NOT') +
|
||||||
|
'supported' +
|
||||||
|
'\n avc: ' +
|
||||||
|
(avcSupported ? '' : 'NOT') +
|
||||||
|
'supported',
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
onLoad = (data: any) => {
|
onLoad = (data: any) => {
|
||||||
this.setState({ duration: data.duration, loading: false, });
|
this.setState({ duration: data.duration, loading: false, });
|
||||||
this.onAudioTracks(data.audioTracks)
|
this.onAudioTracks(data.audioTracks)
|
||||||
@ -288,6 +310,18 @@ class VideoPlayer extends Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderInfoControl() {
|
||||||
|
return (
|
||||||
|
<TouchableOpacity
|
||||||
|
onPress={() => {
|
||||||
|
this.popupInfo()
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Text style={[styles.controlOption]}>{'decoderInfo'}</Text>
|
||||||
|
</TouchableOpacity>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
renderFullScreenControl() {
|
renderFullScreenControl() {
|
||||||
return (
|
return (
|
||||||
<TouchableOpacity
|
<TouchableOpacity
|
||||||
@ -541,6 +575,9 @@ class VideoPlayer extends Component {
|
|||||||
</View>
|
</View>
|
||||||
<View style={styles.bottomControls}>
|
<View style={styles.bottomControls}>
|
||||||
<View style={styles.generalControls}>
|
<View style={styles.generalControls}>
|
||||||
|
<View style={styles.generalControls}>
|
||||||
|
<View style={styles.resizeModeControl}>{this.renderInfoControl()}</View>
|
||||||
|
</View>
|
||||||
<View style={styles.resizeModeControl}>{this.renderPause()}</View>
|
<View style={styles.resizeModeControl}>{this.renderPause()}</View>
|
||||||
<View style={styles.resizeModeControl}>
|
<View style={styles.resizeModeControl}>
|
||||||
{this.renderRepeatModeControl()}
|
{this.renderRepeatModeControl()}
|
||||||
|
Loading…
Reference in New Issue
Block a user