refactor: internal refactor for prepare new arch (#3980)
* chore(js): fix typo * refactor(js): refactor type code for codegen * refactor(js): refactor Video component - parse shutterColor value within JS - remove internal fullscreen state * chore(js): add deprecation warning comment * fix(js): fix return type * fix(js): fix import path * refactor(android): apply changed API for new arch * refactor(ios): apply changed API for new arch * fix(ios): fix wrong name * refactor: refactor VideoDecoderProperties - rename and add wrapper * refactor(android): Code fixes for backward compatibility with Kotlin
This commit is contained in:
parent
de8ade0620
commit
c2084c2ace
@ -47,7 +47,7 @@ enum class EventTypes(val eventName: String) {
|
||||
companion object {
|
||||
fun toMap() =
|
||||
mutableMapOf<String, Any>().apply {
|
||||
EventTypes.entries.forEach { eventType ->
|
||||
EventTypes.values().toList().forEach { eventType ->
|
||||
put("top${eventType.eventName.removePrefix("on")}", mapOf("registrationName" to eventType.eventName))
|
||||
}
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.media3.common.util.Util;
|
||||
|
||||
import com.brentvatne.common.api.BufferConfig;
|
||||
import com.brentvatne.common.api.BufferingStrategy;
|
||||
@ -203,7 +202,7 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_TEXT_TRACKS)
|
||||
public void setPropTextTracks(final ReactExoplayerView videoView,
|
||||
public void setTextTracks(final ReactExoplayerView videoView,
|
||||
@Nullable ReadableArray textTracks) {
|
||||
SideLoadedTextTrackList sideLoadedTextTracks = SideLoadedTextTrackList.Companion.parse(textTracks);
|
||||
videoView.setTextTracks(sideLoadedTextTracks);
|
||||
@ -245,12 +244,12 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_MAXIMUM_BIT_RATE)
|
||||
public void setMaxBitRate(final ReactExoplayerView videoView, final int maxBitRate) {
|
||||
videoView.setMaxBitRateModifier(maxBitRate);
|
||||
public void setMaxBitRate(final ReactExoplayerView videoView, final float maxBitRate) {
|
||||
videoView.setMaxBitRateModifier((int)maxBitRate);
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_MIN_LOAD_RETRY_COUNT)
|
||||
public void minLoadRetryCount(final ReactExoplayerView videoView, final int minLoadRetryCount) {
|
||||
public void setMinLoadRetryCount(final ReactExoplayerView videoView, final int minLoadRetryCount) {
|
||||
videoView.setMinLoadRetryCountModifier(minLoadRetryCount);
|
||||
}
|
||||
|
||||
@ -310,12 +309,11 @@ public class ReactExoplayerViewManager extends ViewGroupManager<ReactExoplayerVi
|
||||
videoView.setSubtitleStyle(SubtitleStyle.parse(src));
|
||||
}
|
||||
|
||||
@ReactProp(name = PROP_SHUTTER_COLOR, customType = "Color")
|
||||
public void setShutterColor(final ReactExoplayerView videoView, final Integer color) {
|
||||
videoView.setShutterColor(color == null ? Color.BLACK : color);
|
||||
@ReactProp(name = PROP_SHUTTER_COLOR, defaultInt = 0)
|
||||
public void setShutterColor(final ReactExoplayerView videoView, final int color) {
|
||||
videoView.setShutterColor(color == 0 ? Color.BLACK : color);
|
||||
}
|
||||
|
||||
|
||||
@ReactProp(name = PROP_BUFFER_CONFIG)
|
||||
public void setBufferConfig(final ReactExoplayerView videoView, @Nullable ReadableMap bufferConfig) {
|
||||
BufferConfig config = BufferConfig.parse(bufferConfig);
|
||||
|
@ -13,7 +13,7 @@ class ReactVideoPackage(private val config: ReactExoplayerConfig? = null) : Reac
|
||||
|
||||
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> =
|
||||
listOf(
|
||||
VideoDecoderPropertiesModule(reactContext),
|
||||
VideoDecoderInfoModule(reactContext),
|
||||
VideoManagerModule(reactContext)
|
||||
)
|
||||
|
||||
|
@ -11,7 +11,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule
|
||||
import com.facebook.react.bridge.ReactMethod
|
||||
import java.util.UUID
|
||||
|
||||
class VideoDecoderPropertiesModule(reactContext: ReactApplicationContext?) : ReactContextBaseJavaModule(reactContext) {
|
||||
class VideoDecoderInfoModule(reactContext: ReactApplicationContext?) : ReactContextBaseJavaModule(reactContext) {
|
||||
override fun getName(): String = REACT_CLASS
|
||||
|
||||
@ReactMethod
|
||||
@ -37,36 +37,36 @@ class VideoDecoderPropertiesModule(reactContext: ReactApplicationContext?) : Rea
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun isCodecSupported(mimeType: String?, width: Int, height: Int, p: Promise) {
|
||||
fun isCodecSupported(mimeType: String?, width: Double, height: Double, p: Promise?) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
|
||||
p.resolve("unsupported")
|
||||
p?.resolve("unsupported")
|
||||
return
|
||||
}
|
||||
val mRegularCodecs = MediaCodecList(MediaCodecList.REGULAR_CODECS)
|
||||
val format = MediaFormat.createVideoFormat(mimeType!!, width, height)
|
||||
val format = MediaFormat.createVideoFormat(mimeType!!, width.toInt(), height.toInt())
|
||||
val codecName = mRegularCodecs.findDecoderForFormat(format)
|
||||
if (codecName == null) {
|
||||
p.resolve("unsupported")
|
||||
p?.resolve("unsupported")
|
||||
return
|
||||
}
|
||||
|
||||
// Fallback for android < 10
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
|
||||
p.resolve("software")
|
||||
p?.resolve("software")
|
||||
return
|
||||
}
|
||||
val isHardwareAccelerated = mRegularCodecs.codecInfos.any {
|
||||
it.name.equals(codecName, ignoreCase = true) && it.isHardwareAccelerated
|
||||
}
|
||||
p.resolve(if (isHardwareAccelerated) "software" else "hardware")
|
||||
p?.resolve(if (isHardwareAccelerated) "software" else "hardware")
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun isHEVCSupported(p: Promise) = isCodecSupported("video/hevc", 1920, 1080, p)
|
||||
fun isHEVCSupported(p: Promise) = isCodecSupported("video/hevc", 1920.0, 1080.0, p)
|
||||
|
||||
companion object {
|
||||
private val WIDEVINE_UUID = UUID(-0x121074568629b532L, -0x5c37d8232ae2de13L)
|
||||
private const val SECURITY_LEVEL_PROPERTY = "securityLevel"
|
||||
private const val REACT_CLASS = "VideoDecoderProperties"
|
||||
private const val REACT_CLASS = "VideoDecoderInfoModule"
|
||||
}
|
||||
}
|
@ -1,12 +1,10 @@
|
||||
package com.brentvatne.react
|
||||
|
||||
import com.brentvatne.common.toolbox.ReactBridgeUtils
|
||||
import com.brentvatne.exoplayer.ReactExoplayerView
|
||||
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 com.facebook.react.bridge.ReadableMap
|
||||
import com.facebook.react.bridge.UiThreadUtil
|
||||
import com.facebook.react.uimanager.UIManagerHelper
|
||||
import com.facebook.react.uimanager.common.UIManagerType
|
||||
@ -37,31 +35,33 @@ class VideoManagerModule(reactContext: ReactApplicationContext?) : ReactContextB
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun setPlayerPauseState(paused: Boolean?, reactTag: Int) {
|
||||
fun setPlayerPauseStateCmd(reactTag: Int, paused: Boolean?) {
|
||||
performOnPlayerView(reactTag) {
|
||||
it?.setPausedModifier(paused!!)
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun seek(info: ReadableMap, reactTag: Int) {
|
||||
if (!info.hasKey("time")) {
|
||||
return
|
||||
}
|
||||
|
||||
val time = ReactBridgeUtils.safeGetInt(info, "time")
|
||||
fun seekCmd(reactTag: Int, time: Float, tolerance: Float) {
|
||||
performOnPlayerView(reactTag) {
|
||||
it?.seekTo((time * 1000f).roundToInt().toLong())
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun setVolume(volume: Float, reactTag: Int) {
|
||||
fun setVolumeCmd(reactTag: Int, volume: Float) {
|
||||
performOnPlayerView(reactTag) {
|
||||
it?.setVolumeModifier(volume)
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun setFullScreenCmd(reactTag: Int, fullScreen: Boolean) {
|
||||
performOnPlayerView(reactTag) {
|
||||
it?.setFullscreen(fullScreen)
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun getCurrentPosition(reactTag: Int, promise: Promise) {
|
||||
performOnPlayerView(reactTag) {
|
||||
@ -69,13 +69,6 @@ class VideoManagerModule(reactContext: ReactApplicationContext?) : ReactContextB
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
fun setFullScreen(fullScreen: Boolean, reactTag: Int) {
|
||||
performOnPlayerView(reactTag) {
|
||||
it?.setFullscreen(fullScreen)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val REACT_CLASS = "VideoManager"
|
||||
}
|
||||
|
@ -762,15 +762,13 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
||||
}
|
||||
|
||||
@objc
|
||||
func setSeek(_ info: NSDictionary!) {
|
||||
let seekTime: NSNumber! = info["time"] as! NSNumber
|
||||
let seekTolerance: NSNumber! = info["tolerance"] as! NSNumber
|
||||
func setSeek(_ time: NSNumber, _ tolerance: NSNumber) {
|
||||
let item: AVPlayerItem? = _player?.currentItem
|
||||
|
||||
_pendingSeek = true
|
||||
|
||||
guard item != nil, let player = _player, let item, item.status == AVPlayerItem.Status.readyToPlay else {
|
||||
_pendingSeekTime = seekTime.floatValue
|
||||
_pendingSeekTime = time.floatValue
|
||||
return
|
||||
}
|
||||
|
||||
@ -778,15 +776,15 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
||||
player: player,
|
||||
playerItem: item,
|
||||
paused: _paused,
|
||||
seekTime: seekTime.floatValue,
|
||||
seekTolerance: seekTolerance.floatValue
|
||||
seekTime: time.floatValue,
|
||||
seekTolerance: tolerance.floatValue
|
||||
) { [weak self] (_: Bool) in
|
||||
guard let self else { return }
|
||||
|
||||
self._playerObserver.addTimeObserverIfNotSet()
|
||||
self.setPaused(self._paused)
|
||||
self.onVideoSeek?(["currentTime": NSNumber(value: Float(CMTimeGetSeconds(item.currentTime()))),
|
||||
"seekTime": seekTime,
|
||||
"seekTime": time,
|
||||
"target": self.reactTag])
|
||||
}
|
||||
|
||||
@ -1303,7 +1301,7 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
||||
// MARK: - Export
|
||||
|
||||
@objc
|
||||
func save(options: NSDictionary!, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||
func save(_ options: NSDictionary!, _ resolve: @escaping RCTPromiseResolveBlock, _ reject: @escaping RCTPromiseRejectBlock) {
|
||||
RCTVideoSave.save(
|
||||
options: options,
|
||||
resolve: resolve,
|
||||
@ -1320,14 +1318,6 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
||||
_resouceLoaderDelegate?.setLicenseResultError(error, licenseUrl)
|
||||
}
|
||||
|
||||
func dismissFullscreenPlayer() {
|
||||
setFullscreen(false)
|
||||
}
|
||||
|
||||
func presentFullscreenPlayer() {
|
||||
setFullscreen(true)
|
||||
}
|
||||
|
||||
// MARK: - RCTPlayerObserverHandler
|
||||
|
||||
func handleTimeUpdate(time _: CMTime) {
|
||||
@ -1381,18 +1371,12 @@ class RCTVideo: UIView, RCTVideoPlayerViewControllerDelegate, RCTPlayerObserverH
|
||||
|
||||
Task {
|
||||
if self._pendingSeek {
|
||||
self.setSeek([
|
||||
"time": NSNumber(value: self._pendingSeekTime),
|
||||
"tolerance": NSNumber(value: 100),
|
||||
])
|
||||
self.setSeek(NSNumber(value: self._pendingSeekTime), NSNumber(value: 100))
|
||||
self._pendingSeek = false
|
||||
}
|
||||
|
||||
if self._startPosition >= 0 {
|
||||
self.setSeek([
|
||||
"time": NSNumber(value: self._startPosition),
|
||||
"tolerance": NSNumber(value: 100),
|
||||
])
|
||||
self.setSeek(NSNumber(value: self._startPosition), NSNumber(value: 100))
|
||||
self._startPosition = -1
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
#import "React/RCTViewManager.h"
|
||||
#import <React/RCTBridge.h>
|
||||
#import <React/RCTBridgeModule.h>
|
||||
|
||||
@interface RCT_EXTERN_MODULE (RCTVideoManager, RCTViewManager)
|
||||
|
||||
@ -37,7 +37,7 @@ RCT_EXPORT_VIEW_PROPERTY(progressUpdateInterval, float);
|
||||
RCT_EXPORT_VIEW_PROPERTY(restoreUserInterfaceForPIPStopCompletionHandler, BOOL);
|
||||
RCT_EXPORT_VIEW_PROPERTY(localSourceEncryptionKeyScheme, NSString);
|
||||
RCT_EXPORT_VIEW_PROPERTY(subtitleStyle, NSDictionary);
|
||||
RCT_EXPORT_VIEW_PROPERTY(showNotificationControls, BOOL)
|
||||
RCT_EXPORT_VIEW_PROPERTY(showNotificationControls, BOOL);
|
||||
/* Should support: onLoadStart, onLoad, and onError to stay consistent with Image */
|
||||
RCT_EXPORT_VIEW_PROPERTY(onVideoLoadStart, RCTDirectEventBlock);
|
||||
RCT_EXPORT_VIEW_PROPERTY(onVideoLoad, RCTDirectEventBlock);
|
||||
@ -68,31 +68,21 @@ RCT_EXPORT_VIEW_PROPERTY(onTextTracks, RCTDirectEventBlock);
|
||||
RCT_EXPORT_VIEW_PROPERTY(onAudioTracks, RCTDirectEventBlock);
|
||||
RCT_EXPORT_VIEW_PROPERTY(onTextTrackDataChanged, RCTDirectEventBlock);
|
||||
|
||||
RCT_EXTERN_METHOD(seekCmd : (nonnull NSNumber*)reactTag time : (nonnull NSNumber*)time tolerance : (nonnull NSNumber*)tolerance)
|
||||
RCT_EXTERN_METHOD(setLicenseResultCmd : (nonnull NSNumber*)reactTag lisence : (NSString*)license licenseUrl : (NSString*)licenseUrl)
|
||||
RCT_EXTERN_METHOD(setLicenseResultErrorCmd : (nonnull NSNumber*)reactTag error : (NSString*)error licenseUrl : (NSString*)licenseUrl)
|
||||
RCT_EXTERN_METHOD(setPlayerPauseStateCmd : (nonnull NSNumber*)reactTag paused : (nonnull BOOL)paused)
|
||||
RCT_EXTERN_METHOD(setVolumeCmd : (nonnull NSNumber*)reactTag volume : (nonnull float*)volume)
|
||||
RCT_EXTERN_METHOD(setFullScreenCmd : (nonnull NSNumber*)reactTag fullscreen : (nonnull BOOL)fullScreen)
|
||||
|
||||
RCT_EXTERN_METHOD(save
|
||||
: (NSDictionary*)options reactTag
|
||||
: (nonnull NSNumber*)reactTag resolver
|
||||
: (RCTPromiseResolveBlock)resolve rejecter
|
||||
: (nonnull NSNumber*)reactTag options
|
||||
: (NSDictionary*)options resolve
|
||||
: (RCTPromiseResolveBlock)resolve reject
|
||||
: (RCTPromiseRejectBlock)reject)
|
||||
|
||||
RCT_EXTERN_METHOD(seek : (NSDictionary*)info reactTag : (nonnull NSNumber*)reactTag)
|
||||
|
||||
RCT_EXTERN_METHOD(setLicenseResult : (NSString*)license licenseUrl : (NSString*)licenseUrl reactTag : (nonnull NSNumber*)reactTag)
|
||||
|
||||
RCT_EXTERN_METHOD(setLicenseResultError : (NSString*)error licenseUrl : (NSString*)licenseUrl reactTag : (nonnull NSNumber*)reactTag)
|
||||
|
||||
RCT_EXTERN_METHOD(setPlayerPauseState : (nonnull NSNumber*)paused reactTag : (nonnull NSNumber*)reactTag)
|
||||
|
||||
RCT_EXTERN_METHOD(presentFullscreenPlayer : (nonnull NSNumber*)reactTag)
|
||||
|
||||
RCT_EXTERN_METHOD(dismissFullscreenPlayer : (nonnull NSNumber*)reactTag)
|
||||
|
||||
RCT_EXTERN_METHOD(setVolume : (nonnull float*)volume reactTag : (nonnull NSNumber*)reactTag)
|
||||
|
||||
RCT_EXTERN_METHOD(getCurrentPosition
|
||||
: (nonnull NSNumber*)reactTag resolver
|
||||
: (RCTPromiseResolveBlock)resolve rejecter
|
||||
: (nonnull NSNumber*)reactTag resolve
|
||||
: (RCTPromiseResolveBlock)resolve reject
|
||||
: (RCTPromiseRejectBlock)reject)
|
||||
|
||||
RCT_EXTERN_METHOD(setFullScreen : (BOOL)fullScreen reactTag : (nonnull NSNumber*)reactTag)
|
||||
|
||||
@end
|
||||
|
@ -30,76 +30,62 @@ class RCTVideoManager: RCTViewManager {
|
||||
}
|
||||
}
|
||||
|
||||
@objc(save:reactTag:resolver:rejecter:)
|
||||
func save(options: NSDictionary, reactTag: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||
@objc(seekCmd:time:tolerance:)
|
||||
func seekCmd(_ reactTag: NSNumber, time: NSNumber, tolerance: NSNumber) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.save(options: options, resolve: resolve, reject: reject)
|
||||
videoView?.setSeek(time, tolerance)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(seek:reactTag:)
|
||||
func seek(info: NSDictionary, reactTag: NSNumber) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.setSeek(info)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(setLicenseResult:licenseUrl:reactTag:)
|
||||
func setLicenseResult(license: NSString, licenseUrl: NSString, reactTag: NSNumber) {
|
||||
@objc(setLicenseResultCmd:license:licenseUrl:)
|
||||
func setLicenseResultCmd(_ reactTag: NSNumber, license: NSString, licenseUrl: NSString) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.setLicenseResult(license as String, licenseUrl as String)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(setLicenseResultError:licenseUrl:reactTag:)
|
||||
func setLicenseResultError(error: NSString, licenseUrl: NSString, reactTag: NSNumber) {
|
||||
@objc(setLicenseResultErrorCmd:error:licenseUrl:)
|
||||
func setLicenseResultErrorCmd(_ reactTag: NSNumber, error: NSString, licenseUrl: NSString) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.setLicenseResultError(error as String, licenseUrl as String)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(dismissFullscreenPlayer:)
|
||||
func dismissFullscreenPlayer(_ reactTag: NSNumber) {
|
||||
@objc(setPlayerPauseStateCmd:paused:)
|
||||
func setPlayerPauseStateCmd(_ reactTag: NSNumber, paused: Bool) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.dismissFullscreenPlayer()
|
||||
videoView?.setPaused(paused)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(presentFullscreenPlayer:)
|
||||
func presentFullscreenPlayer(_ reactTag: NSNumber) {
|
||||
@objc(setVolumeCmd:volume:)
|
||||
func setVolumeCmd(_ reactTag: NSNumber, volume: Float) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.presentFullscreenPlayer()
|
||||
videoView?.setVolume(volume)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(setPlayerPauseState:reactTag:)
|
||||
func setPlayerPauseState(paused: NSNumber, reactTag: NSNumber) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.setPaused(paused.boolValue)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(setVolume:reactTag:)
|
||||
func setVolume(value: Float, reactTag: NSNumber) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.setVolume(value)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(getCurrentPosition:resolver:rejecter:)
|
||||
func getCurrentPosition(reactTag: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.getCurrentPlaybackTime(resolve, reject)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(setFullScreen:reactTag:)
|
||||
func setFullScreen(fullScreen: Bool, reactTag: NSNumber) {
|
||||
@objc(setFullScreenCmd:fullscreen:)
|
||||
func setFullScreenCmd(_ reactTag: NSNumber, fullScreen: Bool) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.setFullscreen(fullScreen)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(save:options:resolve:reject:)
|
||||
func save(_ reactTag: NSNumber, options: NSDictionary, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.save(options, resolve, reject)
|
||||
})
|
||||
}
|
||||
|
||||
@objc(getCurrentPosition:resolve:reject:)
|
||||
func getCurrentPosition(_ reactTag: NSNumber, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
|
||||
performOnVideoView(withReactTag: reactTag, callback: { videoView in
|
||||
videoView?.getCurrentPlaybackTime(resolve, reject)
|
||||
})
|
||||
}
|
||||
|
||||
override class func requiresMainQueueSetup() -> Bool {
|
||||
return true
|
||||
}
|
||||
|
235
src/Video.tsx
235
src/Video.tsx
@ -5,57 +5,47 @@ import React, {
|
||||
useRef,
|
||||
forwardRef,
|
||||
useImperativeHandle,
|
||||
type ComponentRef,
|
||||
} from 'react';
|
||||
import {
|
||||
View,
|
||||
StyleSheet,
|
||||
Image,
|
||||
Platform,
|
||||
type StyleProp,
|
||||
type ImageStyle,
|
||||
type NativeSyntheticEvent,
|
||||
} from 'react-native';
|
||||
import type {ElementRef} from 'react';
|
||||
import {View, StyleSheet, Image, Platform, processColor} from 'react-native';
|
||||
import type {StyleProp, ImageStyle, NativeSyntheticEvent} from 'react-native';
|
||||
|
||||
import NativeVideoComponent, {
|
||||
type OnAudioFocusChangedData,
|
||||
type OnAudioTracksData,
|
||||
type OnBandwidthUpdateData,
|
||||
type OnBufferData,
|
||||
type OnControlsVisibilityChange,
|
||||
type OnExternalPlaybackChangeData,
|
||||
type OnGetLicenseData,
|
||||
type OnLoadStartData,
|
||||
type OnPictureInPictureStatusChangedData,
|
||||
type OnPlaybackStateChangedData,
|
||||
type OnProgressData,
|
||||
type OnSeekData,
|
||||
type OnTextTrackDataChangedData,
|
||||
type OnTimedMetadataData,
|
||||
type OnVideoAspectRatioData,
|
||||
type OnVideoErrorData,
|
||||
type OnVideoTracksData,
|
||||
type VideoComponentType,
|
||||
type VideoSrc,
|
||||
import NativeVideoComponent from './specs/VideoNativeComponent';
|
||||
import type {
|
||||
OnAudioFocusChangedData,
|
||||
OnAudioTracksData,
|
||||
OnBandwidthUpdateData,
|
||||
OnBufferData,
|
||||
OnControlsVisibilityChange,
|
||||
OnExternalPlaybackChangeData,
|
||||
OnGetLicenseData,
|
||||
OnLoadStartData,
|
||||
OnPictureInPictureStatusChangedData,
|
||||
OnPlaybackStateChangedData,
|
||||
OnProgressData,
|
||||
OnSeekData,
|
||||
OnTextTrackDataChangedData,
|
||||
OnTimedMetadataData,
|
||||
OnVideoAspectRatioData,
|
||||
OnVideoErrorData,
|
||||
OnVideoTracksData,
|
||||
VideoSrc,
|
||||
} from './specs/VideoNativeComponent';
|
||||
import {
|
||||
generateHeaderForNative,
|
||||
getReactTag,
|
||||
resolveAssetSourceForVideo,
|
||||
} from './utils';
|
||||
import {VideoManager} from './specs/VideoNativeComponent';
|
||||
import {
|
||||
type OnLoadData,
|
||||
type OnTextTracksData,
|
||||
type OnReceiveAdEventData,
|
||||
type ReactVideoProps,
|
||||
ViewType,
|
||||
import NativeVideoManager from './specs/NativeVideoManager';
|
||||
import type {VideoSaveData} from './specs/NativeVideoManager';
|
||||
import {ViewType} from './types';
|
||||
import type {
|
||||
OnLoadData,
|
||||
OnTextTracksData,
|
||||
OnReceiveAdEventData,
|
||||
ReactVideoProps,
|
||||
} from './types';
|
||||
|
||||
export type VideoSaveData = {
|
||||
uri: string;
|
||||
};
|
||||
|
||||
export interface VideoRef {
|
||||
seek: (time: number, tolerance?: number) => void;
|
||||
resume: () => void;
|
||||
@ -65,10 +55,10 @@ export interface VideoRef {
|
||||
restoreUserInterfaceForPictureInPictureStopCompleted: (
|
||||
restore: boolean,
|
||||
) => void;
|
||||
save: (options: object) => Promise<VideoSaveData>;
|
||||
setVolume: (volume: number) => void;
|
||||
getCurrentPosition: () => Promise<number>;
|
||||
setFullScreen: (fullScreen: boolean) => void;
|
||||
save: (options: object) => Promise<VideoSaveData> | void;
|
||||
getCurrentPosition: () => Promise<number>;
|
||||
}
|
||||
|
||||
const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
@ -79,7 +69,6 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
resizeMode,
|
||||
posterResizeMode,
|
||||
poster,
|
||||
fullscreen,
|
||||
drm,
|
||||
textTracks,
|
||||
selectedVideoTrack,
|
||||
@ -88,6 +77,7 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
useTextureView,
|
||||
useSecureView,
|
||||
viewType,
|
||||
shutterColor,
|
||||
onLoadStart,
|
||||
onLoad,
|
||||
onError,
|
||||
@ -122,9 +112,8 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
},
|
||||
ref,
|
||||
) => {
|
||||
const nativeRef = useRef<ComponentRef<VideoComponentType>>(null);
|
||||
const nativeRef = useRef<ElementRef<typeof NativeVideoComponent>>(null);
|
||||
const [showPoster, setShowPoster] = useState(!!poster);
|
||||
const [isFullscreen, setIsFullscreen] = useState(fullscreen);
|
||||
const [
|
||||
_restoreUserInterfaceForPIPStopCompletionHandler,
|
||||
setRestoreUserInterfaceForPIPStopCompletionHandler,
|
||||
@ -274,12 +263,10 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
}
|
||||
|
||||
const callSeekFunction = () => {
|
||||
VideoManager.seek(
|
||||
{
|
||||
time,
|
||||
tolerance: tolerance || 0,
|
||||
},
|
||||
NativeVideoManager.seekCmd(
|
||||
getReactTag(nativeRef),
|
||||
time,
|
||||
tolerance || 0,
|
||||
);
|
||||
};
|
||||
|
||||
@ -287,31 +274,59 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
ios: callSeekFunction,
|
||||
android: callSeekFunction,
|
||||
default: () => {
|
||||
// TODO: Implement VideoManager.seek for windows
|
||||
// TODO: Implement VideoManager.seekCmd for windows
|
||||
nativeRef.current?.setNativeProps({seek: time});
|
||||
},
|
||||
})();
|
||||
}, []);
|
||||
|
||||
const presentFullscreenPlayer = useCallback(() => {
|
||||
setIsFullscreen(true);
|
||||
}, [setIsFullscreen]);
|
||||
|
||||
const dismissFullscreenPlayer = useCallback(() => {
|
||||
setIsFullscreen(false);
|
||||
}, [setIsFullscreen]);
|
||||
|
||||
const save = useCallback((options: object) => {
|
||||
// VideoManager.save can be null on android & windows
|
||||
return VideoManager.save?.(options, getReactTag(nativeRef));
|
||||
}, []);
|
||||
|
||||
const pause = useCallback(() => {
|
||||
return VideoManager.setPlayerPauseState(true, getReactTag(nativeRef));
|
||||
return NativeVideoManager.setPlayerPauseStateCmd(
|
||||
getReactTag(nativeRef),
|
||||
true,
|
||||
);
|
||||
}, []);
|
||||
|
||||
const resume = useCallback(() => {
|
||||
return VideoManager.setPlayerPauseState(false, getReactTag(nativeRef));
|
||||
return NativeVideoManager.setPlayerPauseStateCmd(
|
||||
getReactTag(nativeRef),
|
||||
false,
|
||||
);
|
||||
}, []);
|
||||
|
||||
const setVolume = useCallback((volume: number) => {
|
||||
return NativeVideoManager.setVolumeCmd(getReactTag(nativeRef), volume);
|
||||
}, []);
|
||||
|
||||
const setFullScreen = useCallback((fullScreen: boolean) => {
|
||||
return NativeVideoManager.setFullScreenCmd(
|
||||
getReactTag(nativeRef),
|
||||
fullScreen,
|
||||
);
|
||||
}, []);
|
||||
|
||||
const presentFullscreenPlayer = useCallback(
|
||||
() => setFullScreen(true),
|
||||
[setFullScreen],
|
||||
);
|
||||
|
||||
const dismissFullscreenPlayer = useCallback(
|
||||
() => setFullScreen(false),
|
||||
[setFullScreen],
|
||||
);
|
||||
|
||||
const save = useCallback((options: object) => {
|
||||
// VideoManager.save can be null on android & windows
|
||||
if (Platform.OS !== 'ios') {
|
||||
return;
|
||||
}
|
||||
// @todo Must implement it in a different way.
|
||||
return NativeVideoManager.save?.(getReactTag(nativeRef), options);
|
||||
}, []);
|
||||
|
||||
const getCurrentPosition = useCallback(() => {
|
||||
// @todo Must implement it in a different way.
|
||||
return NativeVideoManager.getCurrentPosition(getReactTag(nativeRef));
|
||||
}, []);
|
||||
|
||||
const restoreUserInterfaceForPictureInPictureStopCompleted = useCallback(
|
||||
@ -321,18 +336,6 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
[setRestoreUserInterfaceForPIPStopCompletionHandler],
|
||||
);
|
||||
|
||||
const setVolume = useCallback((volume: number) => {
|
||||
return VideoManager.setVolume(volume, getReactTag(nativeRef));
|
||||
}, []);
|
||||
|
||||
const getCurrentPosition = useCallback(() => {
|
||||
return VideoManager.getCurrentPosition(getReactTag(nativeRef));
|
||||
}, []);
|
||||
|
||||
const setFullScreen = useCallback((fullScreen: boolean) => {
|
||||
return VideoManager.setFullScreen(fullScreen, getReactTag(nativeRef));
|
||||
}, []);
|
||||
|
||||
const onVideoLoadStart = useCallback(
|
||||
(e: NativeSyntheticEvent<OnLoadStartData>) => {
|
||||
hasPoster && setShowPoster(true);
|
||||
@ -379,6 +382,11 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
[onPlaybackStateChanged],
|
||||
);
|
||||
|
||||
const _shutterColor = useMemo(() => {
|
||||
const color = processColor(shutterColor);
|
||||
return typeof color === 'number' ? color : undefined;
|
||||
}, [shutterColor]);
|
||||
|
||||
// android only
|
||||
const _onTimedMetadata = useCallback(
|
||||
(e: NativeSyntheticEvent<OnTimedMetadataData>) => {
|
||||
@ -494,56 +502,41 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
[onControlsVisibilityChange],
|
||||
);
|
||||
|
||||
const useExternalGetLicense = drm?.getLicense instanceof Function;
|
||||
const usingExternalGetLicense = drm?.getLicense instanceof Function;
|
||||
|
||||
const onGetLicense = useCallback(
|
||||
(event: NativeSyntheticEvent<OnGetLicenseData>) => {
|
||||
if (useExternalGetLicense) {
|
||||
const data = event.nativeEvent;
|
||||
if (data && data.spcBase64) {
|
||||
const getLicenseOverride = drm.getLicense(
|
||||
async (event: NativeSyntheticEvent<OnGetLicenseData>) => {
|
||||
if (!usingExternalGetLicense) {
|
||||
return;
|
||||
}
|
||||
const data = event.nativeEvent;
|
||||
let result;
|
||||
if (data?.spcBase64) {
|
||||
try {
|
||||
// Handles both scenarios, getLicenseOverride being a promise and not.
|
||||
const license = await drm.getLicense(
|
||||
data.spcBase64,
|
||||
data.contentId,
|
||||
data.licenseUrl,
|
||||
data.loadedLicenseUrl,
|
||||
);
|
||||
const getLicensePromise = Promise.resolve(getLicenseOverride); // Handles both scenarios, getLicenseOverride being a promise and not.
|
||||
getLicensePromise
|
||||
.then((result) => {
|
||||
if (result !== undefined) {
|
||||
nativeRef.current &&
|
||||
VideoManager.setLicenseResult(
|
||||
result,
|
||||
data.loadedLicenseUrl,
|
||||
getReactTag(nativeRef),
|
||||
);
|
||||
} else {
|
||||
nativeRef.current &&
|
||||
VideoManager.setLicenseResultError(
|
||||
'Empty license result',
|
||||
data.loadedLicenseUrl,
|
||||
getReactTag(nativeRef),
|
||||
);
|
||||
}
|
||||
})
|
||||
.catch(() => {
|
||||
nativeRef.current &&
|
||||
VideoManager.setLicenseResultError(
|
||||
'fetch error',
|
||||
data.loadedLicenseUrl,
|
||||
getReactTag(nativeRef),
|
||||
);
|
||||
});
|
||||
} else {
|
||||
VideoManager.setLicenseResultError(
|
||||
'No spc received',
|
||||
data.loadedLicenseUrl,
|
||||
getReactTag(nativeRef),
|
||||
);
|
||||
result =
|
||||
typeof license === 'string' ? license : 'Empty license result';
|
||||
} catch {
|
||||
result = 'fetch error';
|
||||
}
|
||||
} else {
|
||||
result = 'No spc received';
|
||||
}
|
||||
if (nativeRef.current) {
|
||||
NativeVideoManager.setLicenseResultErrorCmd(
|
||||
getReactTag(nativeRef),
|
||||
result,
|
||||
data.loadedLicenseUrl,
|
||||
);
|
||||
}
|
||||
},
|
||||
[drm, useExternalGetLicense],
|
||||
[drm, usingExternalGetLicense],
|
||||
);
|
||||
|
||||
useImperativeHandle(
|
||||
@ -613,7 +606,6 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
src={src}
|
||||
style={StyleSheet.absoluteFill}
|
||||
resizeMode={resizeMode}
|
||||
fullscreen={isFullscreen}
|
||||
restoreUserInterfaceForPIPStopCompletionHandler={
|
||||
_restoreUserInterfaceForPIPStopCompletionHandler
|
||||
}
|
||||
@ -621,7 +613,8 @@ const Video = forwardRef<VideoRef, ReactVideoProps>(
|
||||
selectedTextTrack={_selectedTextTrack}
|
||||
selectedAudioTrack={_selectedAudioTrack}
|
||||
selectedVideoTrack={_selectedVideoTrack}
|
||||
onGetLicense={useExternalGetLicense ? onGetLicense : undefined}
|
||||
shutterColor={_shutterColor}
|
||||
onGetLicense={usingExternalGetLicense ? onGetLicense : undefined}
|
||||
onVideoLoad={
|
||||
onLoad || hasPoster
|
||||
? (onVideoLoad as (e: NativeSyntheticEvent<object>) => void)
|
||||
|
29
src/VideoDecoderProperties.ts
Normal file
29
src/VideoDecoderProperties.ts
Normal file
@ -0,0 +1,29 @@
|
||||
import {Platform} from 'react-native';
|
||||
|
||||
import NativeVideoDecoderInfoModule from './specs/NativeVideoDecoderInfoModule';
|
||||
|
||||
const errMsgGen = (moduleName: string, propertyName: string) =>
|
||||
`The method or property ${moduleName}.${propertyName} is not available on ${Platform.OS}.`;
|
||||
|
||||
export const VideoDecoderProperties = {
|
||||
async getWidevineLevel() {
|
||||
if (Platform.OS !== 'android') {
|
||||
throw new Error(errMsgGen('VideoDecoderProperties', 'getWidevineLevel'));
|
||||
}
|
||||
return NativeVideoDecoderInfoModule.getWidevineLevel();
|
||||
},
|
||||
async isCodecSupported(
|
||||
...args: Parameters<typeof NativeVideoDecoderInfoModule.isCodecSupported>
|
||||
) {
|
||||
if (Platform.OS !== 'android') {
|
||||
throw new Error(errMsgGen('VideoDecoderProperties', 'isCodecSupported'));
|
||||
}
|
||||
return NativeVideoDecoderInfoModule.isCodecSupported(...args);
|
||||
},
|
||||
async isHEVCSupported() {
|
||||
if (Platform.OS !== 'android') {
|
||||
throw new Error(errMsgGen('VideoDecoderProperties', 'isHEVCSupported'));
|
||||
}
|
||||
return NativeVideoDecoderInfoModule.isHEVCSupported();
|
||||
},
|
||||
};
|
@ -1,5 +1,5 @@
|
||||
import Video from './Video';
|
||||
export {VideoDecoderProperties} from './specs/VideoNativeComponent';
|
||||
export {VideoDecoderProperties} from './VideoDecoderProperties';
|
||||
export * from './types';
|
||||
export type {VideoRef} from './Video';
|
||||
export default Video;
|
||||
|
15
src/specs/NativeVideoDecoderInfoModule.ts
Normal file
15
src/specs/NativeVideoDecoderInfoModule.ts
Normal file
@ -0,0 +1,15 @@
|
||||
import {NativeModules} from 'react-native';
|
||||
import type {Int32} from 'react-native/Libraries/Types/CodegenTypes';
|
||||
|
||||
// @TODO rename to "Spec" when applying new arch
|
||||
interface VideoDecoderInfoModuleType {
|
||||
getWidevineLevel: () => Promise<Int32>;
|
||||
isCodecSupported: (
|
||||
mimeType: string,
|
||||
width: Int32,
|
||||
height: Int32,
|
||||
) => Promise<'unsupported' | 'hardware' | 'software'>;
|
||||
isHEVCSupported: () => Promise<'unsupported' | 'hardware' | 'software'>;
|
||||
}
|
||||
|
||||
export default NativeModules.VideoDecoderInfoModule as VideoDecoderInfoModuleType;
|
32
src/specs/NativeVideoManager.ts
Normal file
32
src/specs/NativeVideoManager.ts
Normal file
@ -0,0 +1,32 @@
|
||||
import {NativeModules} from 'react-native';
|
||||
import type {
|
||||
Int32,
|
||||
Float,
|
||||
UnsafeObject,
|
||||
} from 'react-native/Libraries/Types/CodegenTypes';
|
||||
|
||||
export type VideoSaveData = {
|
||||
uri: string;
|
||||
};
|
||||
|
||||
// @TODO rename to "Spec" when applying new arch
|
||||
export interface VideoManagerType {
|
||||
seekCmd: (reactTag: Int32, time: Float, tolerance?: Float) => Promise<void>;
|
||||
setPlayerPauseStateCmd: (reactTag: Int32, paused: boolean) => Promise<void>;
|
||||
setLicenseResultCmd: (
|
||||
reactTag: Int32,
|
||||
result: string,
|
||||
licenseUrl: string,
|
||||
) => Promise<void>;
|
||||
setLicenseResultErrorCmd: (
|
||||
reactTag: Int32,
|
||||
error: string,
|
||||
licenseUrl: string,
|
||||
) => Promise<void>;
|
||||
setFullScreenCmd: (reactTag: Int32, fullScreen: boolean) => Promise<void>;
|
||||
setVolumeCmd: (reactTag: Int32, volume: number) => Promise<void>;
|
||||
save: (reactTag: Int32, option: UnsafeObject) => Promise<VideoSaveData>;
|
||||
getCurrentPosition: (reactTag: Int32) => Promise<Int32>;
|
||||
}
|
||||
|
||||
export default NativeModules.VideoManager as VideoManagerType;
|
@ -1,6 +1,6 @@
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
import type {HostComponent, ViewProps} from 'react-native';
|
||||
import {NativeModules, requireNativeComponent} from 'react-native';
|
||||
import {requireNativeComponent} from 'react-native';
|
||||
import type {
|
||||
DirectEventHandler,
|
||||
Double,
|
||||
@ -91,11 +91,6 @@ type SelectedVideoTrack = Readonly<{
|
||||
value?: string;
|
||||
}>;
|
||||
|
||||
export type Seek = Readonly<{
|
||||
time: Float;
|
||||
tolerance?: Float;
|
||||
}>;
|
||||
|
||||
type BufferConfigLive = Readonly<{
|
||||
maxPlaybackSpeed?: Float;
|
||||
minPlaybackSpeed?: Float;
|
||||
@ -289,7 +284,7 @@ export type OnAudioFocusChangedData = Readonly<{
|
||||
|
||||
type ControlsStyles = Readonly<{
|
||||
hideSeekBar?: boolean;
|
||||
seekIncrementMS?: number;
|
||||
seekIncrementMS?: Int32;
|
||||
}>;
|
||||
|
||||
export type OnControlsVisibilityChange = Readonly<{
|
||||
@ -300,10 +295,13 @@ export interface VideoNativeProps extends ViewProps {
|
||||
src?: VideoSrc;
|
||||
adTagUrl?: string;
|
||||
allowsExternalPlayback?: boolean; // ios, true
|
||||
disableFocus?: boolean; // android
|
||||
maxBitRate?: Float;
|
||||
resizeMode?: WithDefault<string, 'none'>;
|
||||
repeat?: boolean;
|
||||
automaticallyWaitsToMinimizeStalling?: boolean;
|
||||
shutterColor?: Int32;
|
||||
audioOutput?: WithDefault<string, 'speaker'>;
|
||||
textTracks?: TextTracks;
|
||||
selectedTextTrack?: SelectedTextTrack;
|
||||
selectedAudioTrack?: SelectedAudioTrack;
|
||||
@ -375,45 +373,8 @@ export interface VideoNativeProps extends ViewProps {
|
||||
onVideoTracks?: DirectEventHandler<OnVideoTracksData>; // android
|
||||
}
|
||||
|
||||
export type VideoComponentType = HostComponent<VideoNativeProps>;
|
||||
|
||||
export type VideoSaveData = {
|
||||
uri: string;
|
||||
};
|
||||
|
||||
export interface VideoManagerType {
|
||||
save: (option: object, reactTag: number) => Promise<VideoSaveData>;
|
||||
seek: (option: Seek, reactTag: number) => Promise<void>;
|
||||
setPlayerPauseState: (paused: boolean, reactTag: number) => Promise<void>;
|
||||
setLicenseResult: (
|
||||
result: string,
|
||||
licenseUrl: string,
|
||||
reactTag: number,
|
||||
) => Promise<void>;
|
||||
setLicenseResultError: (
|
||||
error: string,
|
||||
licenseUrl: string,
|
||||
reactTag: number,
|
||||
) => Promise<void>;
|
||||
setVolume: (volume: number, reactTag: number) => Promise<void>;
|
||||
getCurrentPosition: (reactTag: number) => Promise<number>;
|
||||
setFullScreen: (fullScreen: boolean, reactTag: number) => Promise<void>;
|
||||
}
|
||||
|
||||
export interface VideoDecoderPropertiesType {
|
||||
getWidevineLevel: () => Promise<number>;
|
||||
isCodecSupported: (
|
||||
mimeType: string,
|
||||
width: number,
|
||||
height: number,
|
||||
) => Promise<'unsupported' | 'hardware' | 'software'>;
|
||||
isHEVCSupported: () => Promise<'unsupported' | 'hardware' | 'software'>;
|
||||
}
|
||||
|
||||
export const VideoManager = NativeModules.VideoManager as VideoManagerType;
|
||||
export const VideoDecoderProperties =
|
||||
NativeModules.VideoDecoderProperties as VideoDecoderPropertiesType;
|
||||
type NativeVideoComponentType = HostComponent<VideoNativeProps>;
|
||||
|
||||
export default requireNativeComponent<VideoNativeProps>(
|
||||
'RCTVideo',
|
||||
) as VideoComponentType;
|
||||
) as NativeVideoComponentType;
|
||||
|
@ -2,10 +2,10 @@
|
||||
* Define Available view type for android
|
||||
* these values shall match android spec, see ViewType.kt
|
||||
*/
|
||||
enum ResizeMode {
|
||||
enum ViewType {
|
||||
TEXTURE = 0,
|
||||
SURFACE = 1,
|
||||
SURFACE_SECURE = 2,
|
||||
}
|
||||
|
||||
export default ResizeMode;
|
||||
export default ViewType;
|
||||
|
@ -68,7 +68,7 @@ export type Drm = Readonly<{
|
||||
contentId: string,
|
||||
licenseUrl: string,
|
||||
loadedLicenseUrl: string,
|
||||
) => void; // ios
|
||||
) => string | Promise<string>; // ios
|
||||
/* eslint-enable @typescript-eslint/no-unused-vars */
|
||||
}>;
|
||||
|
||||
|
@ -43,6 +43,10 @@ export function resolveAssetSourceForVideo(
|
||||
return source as ReactVideoSourceProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Do not use this fn anymore. "findNodeHandle" will be deprecated.
|
||||
* */
|
||||
export function getReactTag(
|
||||
ref: RefObject<
|
||||
| Component<unknown, unknown, unknown>
|
||||
|
Loading…
Reference in New Issue
Block a user