react-native-unified-player 0.7.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +432 -130
- package/UnifiedPlayer.podspec +36 -10
- package/android/CMakeLists.txt +29 -0
- package/android/build.gradle +174 -12
- package/android/fix-prefab.gradle +51 -0
- package/android/gradle.properties +11 -2
- package/android/src/main/AndroidManifestNew.xml +7 -2
- package/android/src/main/cpp/cpp-adapter.cpp +6 -0
- package/android/src/main/java/com/unifiedplayer/core/AudioFocusManager.kt +233 -0
- package/android/src/main/java/com/unifiedplayer/core/VideoError.kt +105 -0
- package/android/src/main/java/com/unifiedplayer/core/VideoManager.kt +292 -0
- package/android/src/main/java/com/unifiedplayer/core/extensions/ResizeMode+AspectRatioFrameLayout.kt +20 -0
- package/android/src/main/java/com/unifiedplayer/core/extensions/SubtitleType+toString.kt +14 -0
- package/android/src/main/java/com/unifiedplayer/core/extensions/VideoPlaybackService+ServiceManagment.kt +59 -0
- package/android/src/main/java/com/unifiedplayer/core/fragments/FullscreenVideoFragment.kt +265 -0
- package/android/src/main/java/com/unifiedplayer/core/fragments/PictureInPictureHelperFragment.kt +85 -0
- package/android/src/main/java/com/unifiedplayer/core/player/DRMManagerSpec.kt +23 -0
- package/android/src/main/java/com/unifiedplayer/core/player/DataSourceFactoryUtils.kt +51 -0
- package/android/src/main/java/com/unifiedplayer/core/player/MediaItemUtils.kt +141 -0
- package/android/src/main/java/com/unifiedplayer/core/player/MediaSourceUtils.kt +112 -0
- package/android/src/main/java/com/unifiedplayer/core/player/OnAudioFocusChangedListener.kt +25 -0
- package/android/src/main/java/com/unifiedplayer/core/plugins/PluginsRegistry.kt +223 -0
- package/android/src/main/java/com/unifiedplayer/core/plugins/ReactNativeVideoPlugin.kt +173 -0
- package/android/src/main/java/com/unifiedplayer/core/recivers/AudioBecomingNoisyReceiver.kt +38 -0
- package/android/src/main/java/com/unifiedplayer/core/services/playback/CustomMediaNotificationProvider.kt +151 -0
- package/android/src/main/java/com/unifiedplayer/core/services/playback/VideoPlaybackCallback.kt +96 -0
- package/android/src/main/java/com/unifiedplayer/core/services/playback/VideoPlaybackService.kt +219 -0
- package/android/src/main/java/com/unifiedplayer/core/services/playback/VideoPlaybackServiceConnection.kt +59 -0
- package/android/src/main/java/com/unifiedplayer/core/utils/PictureInPictureUtils.kt +153 -0
- package/android/src/main/java/com/unifiedplayer/core/utils/SmallVideoPlayerOptimizer.kt +157 -0
- package/android/src/main/java/com/unifiedplayer/core/utils/SourceLoader.kt +48 -0
- package/android/src/main/java/com/unifiedplayer/core/utils/TextTrackUtils.kt +175 -0
- package/android/src/main/java/com/unifiedplayer/core/utils/Threading.kt +75 -0
- package/android/src/main/java/com/unifiedplayer/core/utils/VideoFileHelper.kt +51 -0
- package/android/src/main/java/com/unifiedplayer/core/utils/VideoInformationUtils.kt +67 -0
- package/android/src/main/java/com/unifiedplayer/core/utils/VideoOrientationUtils.kt +30 -0
- package/android/src/main/java/com/unifiedplayer/hybrids/videoplayer/HybridVideoPlayer.kt +700 -0
- package/android/src/main/java/com/unifiedplayer/hybrids/videoplayer/HybridVideoPlayerFactory.kt +16 -0
- package/android/src/main/java/com/unifiedplayer/hybrids/videoplayereventemitter/HybridVideoPlayerEventEmitter.kt +180 -0
- package/android/src/main/java/com/unifiedplayer/hybrids/videoplayersource/HybridVideoPlayerSource.kt +67 -0
- package/android/src/main/java/com/unifiedplayer/hybrids/videoplayersource/HybridVideoPlayerSourceFactory.kt +58 -0
- package/android/src/main/java/com/unifiedplayer/hybrids/videoviewviewmanager/HybridVideoViewViewManager.kt +187 -0
- package/android/src/main/java/com/unifiedplayer/hybrids/videoviewviewmanager/HybridVideoViewViewManagerFactory.kt +13 -0
- package/android/src/main/java/com/unifiedplayer/{UnifiedPlayerPackage.kt → react/VideoPackage.kt} +14 -12
- package/android/src/main/java/com/unifiedplayer/react/VideoViewViewManager.kt +78 -0
- package/android/src/main/java/com/unifiedplayer/view/VideoView.kt +565 -0
- package/android/src/main/res/layout/player_view_surface.xml +14 -0
- package/android/src/main/res/layout/player_view_texture.xml +15 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNCVideoViewManagerDelegate.java +32 -0
- package/android/src/paper/java/com/facebook/react/viewmanagers/RNCVideoViewManagerInterface.java +16 -0
- package/android/src/stubs/dash/androidx/media3/exoplayer/dash/DashMediaSource.kt +35 -0
- package/android/src/stubs/dash/androidx/media3/exoplayer/dash/DashUtil.kt +11 -0
- package/android/src/stubs/dash/androidx/media3/exoplayer/dash/manifest/AdaptationSet.kt +9 -0
- package/android/src/stubs/dash/androidx/media3/exoplayer/dash/manifest/DashManifest.kt +10 -0
- package/android/src/stubs/dash/androidx/media3/exoplayer/dash/manifest/Period.kt +7 -0
- package/android/src/stubs/dash/androidx/media3/exoplayer/dash/manifest/Representation.kt +8 -0
- package/android/src/stubs/hls/androidx/media3/exoplayer/hls/HlsMediaSource.kt +33 -0
- package/ios/RNCVideoViewManager.mm +39 -0
- package/ios/Video-Bridging-Header.h +1 -0
- package/ios/core/Extensions/AVAsset+estimatedMemoryUsage.swift +51 -0
- package/ios/core/Extensions/AVAssetTrack+orientation.swift +41 -0
- package/ios/core/Extensions/AVPlayerItem+externalSubtitles.swift +35 -0
- package/ios/core/Extensions/AVPlayerItem+getBufferedDurration.swift +34 -0
- package/ios/core/Extensions/AVPlayerItem+setBufferConfig.swift +37 -0
- package/ios/core/Extensions/AVPlayerViewController+Fullscreen.swift +21 -0
- package/ios/core/Extensions/AVPlayerViewController+PictureInPicture.swift +24 -0
- package/ios/core/Extensions/AVURLAsset+getAssetInformation.swift +68 -0
- package/ios/core/Extensions/NSObject+PerformIfResponds.swift +30 -0
- package/ios/core/Extensions/ResizeMode+VideoGravity.swift +24 -0
- package/ios/core/HLSSubtitleInjector.swift +381 -0
- package/ios/core/NowPlayingInfoCenterManager.swift +323 -0
- package/ios/core/Plugins/PluginsRegistry.swift +102 -0
- package/ios/core/Plugins/ReactNativeVideoPlugin.swift +91 -0
- package/ios/core/Spec/DRMManagerSpec.swift +14 -0
- package/ios/core/Spec/NativeVideoPlayerSourceSpec.swift +36 -0
- package/ios/core/Spec/NativeVideoPlayerSpec.swift +42 -0
- package/ios/core/Utils/ExternalSubtitlesUtils.swift +119 -0
- package/ios/core/Utils/HLSManifestParser.swift +170 -0
- package/ios/core/Utils/Weak.swift +26 -0
- package/ios/core/VideoError.swift +169 -0
- package/ios/core/VideoFileHelper.swift +48 -0
- package/ios/core/VideoManager.swift +412 -0
- package/ios/core/VideoPlayerObserver.swift +294 -0
- package/ios/hybrids/VideoPlayer/HybridVideoPlayer+Events.swift +198 -0
- package/ios/hybrids/VideoPlayer/HybridVideoPlayer.swift +595 -0
- package/ios/hybrids/VideoPlayer/HybridVideoPlayerFactory.swift +15 -0
- package/ios/hybrids/VideoPlayerEmitter/HybridVideoPlayerEventEmitter.swift +203 -0
- package/ios/hybrids/VideoPlayerSource/HybridVideoPlayerSource.swift +166 -0
- package/ios/hybrids/VideoPlayerSource/HybridVideoPlayerSourceFactory.swift +29 -0
- package/ios/hybrids/VideoPlayerSource/SourceLoader.swift +83 -0
- package/ios/hybrids/VideoViewViewManager/HybridVideoViewViewManager.swift +266 -0
- package/ios/hybrids/VideoViewViewManager/HybridVideoViewViewManagerFactory.swift +14 -0
- package/ios/view/VideoComponentView.swift +300 -0
- package/ios/view/VideoComponentViewObserver.swift +144 -0
- package/lib/module/core/VideoPlayer.js +277 -0
- package/lib/module/core/VideoPlayer.js.map +1 -0
- package/lib/module/core/VideoPlayerEvents.js +84 -0
- package/lib/module/core/VideoPlayerEvents.js.map +1 -0
- package/lib/module/core/hooks/useEvent.js +19 -0
- package/lib/module/core/hooks/useEvent.js.map +1 -0
- package/lib/module/core/hooks/useManagedInstance.js +75 -0
- package/lib/module/core/hooks/useManagedInstance.js.map +1 -0
- package/lib/module/core/hooks/useVideoPlayer.js +57 -0
- package/lib/module/core/hooks/useVideoPlayer.js.map +1 -0
- package/lib/module/core/types/BufferConfig.js +2 -0
- package/lib/module/core/types/BufferConfig.js.map +1 -0
- package/lib/module/core/types/DrmParams.js +2 -0
- package/lib/module/core/types/DrmParams.js.map +1 -0
- package/lib/module/core/types/Events.js +10 -0
- package/lib/module/core/types/Events.js.map +1 -0
- package/lib/module/core/types/IgnoreSilentSwitchMode.js +2 -0
- package/lib/module/core/types/IgnoreSilentSwitchMode.js.map +1 -0
- package/lib/module/core/types/MixAudioMode.js +2 -0
- package/lib/module/core/types/MixAudioMode.js.map +1 -0
- package/lib/module/core/types/ResizeMode.js +2 -0
- package/lib/module/core/types/ResizeMode.js.map +1 -0
- package/lib/module/core/types/TextTrack.js +2 -0
- package/lib/module/core/types/TextTrack.js.map +1 -0
- package/lib/module/core/types/Utils.js +2 -0
- package/lib/module/core/types/Utils.js.map +1 -0
- package/lib/module/core/types/VideoConfig.js +4 -0
- package/lib/module/core/types/VideoConfig.js.map +1 -0
- package/lib/module/core/types/VideoError.js +100 -0
- package/lib/module/core/types/VideoError.js.map +1 -0
- package/lib/module/core/types/VideoInformation.js +4 -0
- package/lib/module/core/types/VideoInformation.js.map +1 -0
- package/lib/module/core/types/VideoOrientation.js +2 -0
- package/lib/module/core/types/VideoOrientation.js.map +1 -0
- package/lib/module/core/types/VideoPlayerBase.js +4 -0
- package/lib/module/core/types/VideoPlayerBase.js.map +1 -0
- package/lib/module/core/types/VideoPlayerSourceBase.js +4 -0
- package/lib/module/core/types/VideoPlayerSourceBase.js.map +1 -0
- package/lib/module/core/types/VideoPlayerStatus.js +2 -0
- package/lib/module/core/types/VideoPlayerStatus.js.map +1 -0
- package/lib/module/core/utils/playerFactory.js +25 -0
- package/lib/module/core/utils/playerFactory.js.map +1 -0
- package/lib/module/core/utils/sourceFactory.js +138 -0
- package/lib/module/core/utils/sourceFactory.js.map +1 -0
- package/lib/module/core/video-view/NativeVideoView.js +13 -0
- package/lib/module/core/video-view/NativeVideoView.js.map +1 -0
- package/lib/module/core/video-view/VideoView.js +239 -0
- package/lib/module/core/video-view/VideoView.js.map +1 -0
- package/lib/module/expo-plugins/@types.js +2 -0
- package/lib/module/expo-plugins/@types.js.map +1 -0
- package/lib/module/expo-plugins/getPackageInfo.js +23 -0
- package/lib/module/expo-plugins/getPackageInfo.js.map +1 -0
- package/lib/module/expo-plugins/withAndroidExtensions.js +35 -0
- package/lib/module/expo-plugins/withAndroidExtensions.js.map +1 -0
- package/lib/module/expo-plugins/withAndroidNotificationControls.js +29 -0
- package/lib/module/expo-plugins/withAndroidNotificationControls.js.map +1 -0
- package/lib/module/expo-plugins/withAndroidPictureInPicture.js +18 -0
- package/lib/module/expo-plugins/withAndroidPictureInPicture.js.map +1 -0
- package/lib/module/expo-plugins/withBackgroundAudio.js +22 -0
- package/lib/module/expo-plugins/withBackgroundAudio.js.map +1 -0
- package/lib/module/expo-plugins/withReactNativeVideo.js +27 -0
- package/lib/module/expo-plugins/withReactNativeVideo.js.map +1 -0
- package/lib/module/expo-plugins/writeToPodfile.js +53 -0
- package/lib/module/expo-plugins/writeToPodfile.js.map +1 -0
- package/lib/module/index.js +5 -204
- package/lib/module/index.js.map +1 -1
- package/lib/module/spec/fabric/VideoViewNativeComponent.js +5 -0
- package/lib/module/spec/fabric/VideoViewNativeComponent.js.map +1 -0
- package/lib/module/spec/nitro/VideoPlayer.nitro.js +4 -0
- package/lib/module/spec/nitro/VideoPlayer.nitro.js.map +1 -0
- package/lib/module/spec/nitro/VideoPlayerEventEmitter.nitro.js +4 -0
- package/lib/module/spec/nitro/VideoPlayerEventEmitter.nitro.js.map +1 -0
- package/lib/module/spec/nitro/VideoPlayerSource.nitro.js +4 -0
- package/lib/module/spec/nitro/VideoPlayerSource.nitro.js.map +1 -0
- package/lib/module/spec/nitro/VideoViewViewManager.nitro.js +4 -0
- package/lib/module/spec/nitro/VideoViewViewManager.nitro.js.map +1 -0
- package/lib/typescript/drm-plugin/src/PluginManager.nitro.d.ts +10 -0
- package/lib/typescript/drm-plugin/src/PluginManager.nitro.d.ts.map +1 -0
- package/lib/typescript/drm-plugin/src/index.d.ts +4 -0
- package/lib/typescript/drm-plugin/src/index.d.ts.map +1 -0
- package/lib/typescript/src/core/VideoPlayer.d.ts +86 -0
- package/lib/typescript/src/core/VideoPlayer.d.ts.map +1 -0
- package/lib/typescript/src/core/VideoPlayerEvents.d.ts +22 -0
- package/lib/typescript/src/core/VideoPlayerEvents.d.ts.map +1 -0
- package/lib/typescript/src/core/hooks/useEvent.d.ts +11 -0
- package/lib/typescript/src/core/hooks/useEvent.d.ts.map +1 -0
- package/lib/typescript/src/core/hooks/useManagedInstance.d.ts +19 -0
- package/lib/typescript/src/core/hooks/useManagedInstance.d.ts.map +1 -0
- package/lib/typescript/src/core/hooks/useVideoPlayer.d.ts +16 -0
- package/lib/typescript/src/core/hooks/useVideoPlayer.d.ts.map +1 -0
- package/lib/typescript/src/core/types/BufferConfig.d.ts +97 -0
- package/lib/typescript/src/core/types/BufferConfig.d.ts.map +1 -0
- package/lib/typescript/src/core/types/DrmParams.d.ts +64 -0
- package/lib/typescript/src/core/types/DrmParams.d.ts.map +1 -0
- package/lib/typescript/src/core/types/Events.d.ts +224 -0
- package/lib/typescript/src/core/types/Events.d.ts.map +1 -0
- package/lib/typescript/src/core/types/IgnoreSilentSwitchMode.d.ts +2 -0
- package/lib/typescript/src/core/types/IgnoreSilentSwitchMode.d.ts.map +1 -0
- package/lib/typescript/src/core/types/MixAudioMode.d.ts +2 -0
- package/lib/typescript/src/core/types/MixAudioMode.d.ts.map +1 -0
- package/lib/typescript/src/core/types/ResizeMode.d.ts +10 -0
- package/lib/typescript/src/core/types/ResizeMode.d.ts.map +1 -0
- package/lib/typescript/src/core/types/TextTrack.d.ts +20 -0
- package/lib/typescript/src/core/types/TextTrack.d.ts.map +1 -0
- package/lib/typescript/src/core/types/Utils.d.ts +2 -0
- package/lib/typescript/src/core/types/Utils.d.ts.map +1 -0
- package/lib/typescript/src/core/types/VideoConfig.d.ts +138 -0
- package/lib/typescript/src/core/types/VideoConfig.d.ts.map +1 -0
- package/lib/typescript/src/core/types/VideoError.d.ts +31 -0
- package/lib/typescript/src/core/types/VideoError.d.ts.map +1 -0
- package/lib/typescript/src/core/types/VideoInformation.d.ts +37 -0
- package/lib/typescript/src/core/types/VideoInformation.d.ts.map +1 -0
- package/lib/typescript/src/core/types/VideoOrientation.d.ts +2 -0
- package/lib/typescript/src/core/types/VideoOrientation.d.ts.map +1 -0
- package/lib/typescript/src/core/types/VideoPlayerBase.d.ts +155 -0
- package/lib/typescript/src/core/types/VideoPlayerBase.d.ts.map +1 -0
- package/lib/typescript/src/core/types/VideoPlayerSourceBase.d.ts +17 -0
- package/lib/typescript/src/core/types/VideoPlayerSourceBase.d.ts.map +1 -0
- package/lib/typescript/src/core/types/VideoPlayerStatus.d.ts +9 -0
- package/lib/typescript/src/core/types/VideoPlayerStatus.d.ts.map +1 -0
- package/lib/typescript/src/core/utils/playerFactory.d.ts +12 -0
- package/lib/typescript/src/core/utils/playerFactory.d.ts.map +1 -0
- package/lib/typescript/src/core/utils/sourceFactory.d.ts +29 -0
- package/lib/typescript/src/core/utils/sourceFactory.d.ts.map +1 -0
- package/lib/typescript/src/core/video-view/NativeVideoView.d.ts +2 -0
- package/lib/typescript/src/core/video-view/NativeVideoView.d.ts.map +1 -0
- package/lib/typescript/src/core/video-view/VideoView.d.ts +94 -0
- package/lib/typescript/src/core/video-view/VideoView.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +12 -120
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/spec/fabric/VideoViewNativeComponent.d.ts +12 -0
- package/lib/typescript/src/spec/fabric/VideoViewNativeComponent.d.ts.map +1 -0
- package/lib/typescript/src/spec/nitro/VideoPlayer.nitro.d.ts +55 -0
- package/lib/typescript/src/spec/nitro/VideoPlayer.nitro.d.ts.map +1 -0
- package/lib/typescript/src/spec/nitro/VideoPlayerEventEmitter.nitro.d.ts +150 -0
- package/lib/typescript/src/spec/nitro/VideoPlayerEventEmitter.nitro.d.ts.map +1 -0
- package/lib/typescript/src/spec/nitro/VideoPlayerSource.nitro.d.ts +21 -0
- package/lib/typescript/src/spec/nitro/VideoPlayerSource.nitro.d.ts.map +1 -0
- package/lib/typescript/src/spec/nitro/VideoViewViewManager.nitro.d.ts +75 -0
- package/lib/typescript/src/spec/nitro/VideoViewViewManager.nitro.d.ts.map +1 -0
- package/nitro.json +29 -0
- package/package.json +12 -4
- package/react-native.config.js +10 -0
- package/src/core/VideoPlayer.ts +336 -0
- package/src/core/VideoPlayerEvents.ts +146 -0
- package/src/core/hooks/useEvent.ts +24 -0
- package/src/core/hooks/useManagedInstance.ts +96 -0
- package/src/core/hooks/useVideoPlayer.ts +73 -0
- package/src/core/types/BufferConfig.ts +103 -0
- package/src/core/types/DrmParams.ts +65 -0
- package/src/core/types/Events.ts +283 -0
- package/src/core/types/IgnoreSilentSwitchMode.ts +1 -0
- package/src/core/types/MixAudioMode.ts +1 -0
- package/src/core/types/ResizeMode.ts +9 -0
- package/src/core/types/TextTrack.ts +22 -0
- package/src/core/types/Utils.ts +1 -0
- package/src/core/types/VideoConfig.ts +150 -0
- package/src/core/types/VideoError.ts +174 -0
- package/src/core/types/VideoInformation.ts +44 -0
- package/src/core/types/VideoOrientation.ts +8 -0
- package/src/core/types/VideoPlayerBase.ts +181 -0
- package/src/core/types/VideoPlayerSourceBase.ts +19 -0
- package/src/core/types/VideoPlayerStatus.ts +8 -0
- package/src/core/utils/playerFactory.ts +33 -0
- package/src/core/utils/sourceFactory.ts +171 -0
- package/src/core/video-view/NativeVideoView.tsx +18 -0
- package/src/core/video-view/VideoView.tsx +458 -0
- package/src/expo-plugins/@types.ts +37 -0
- package/src/expo-plugins/getPackageInfo.ts +23 -0
- package/src/expo-plugins/withAndroidExtensions.ts +46 -0
- package/src/expo-plugins/withAndroidNotificationControls.ts +43 -0
- package/src/expo-plugins/withAndroidPictureInPicture.ts +31 -0
- package/src/expo-plugins/withBackgroundAudio.ts +26 -0
- package/src/expo-plugins/withReactNativeVideo.ts +32 -0
- package/src/expo-plugins/writeToPodfile.ts +74 -0
- package/src/index.tsx +29 -376
- package/src/spec/fabric/VideoViewNativeComponent.ts +17 -0
- package/src/spec/nitro/VideoPlayer.nitro.ts +62 -0
- package/src/spec/nitro/VideoPlayerEventEmitter.nitro.ts +207 -0
- package/src/spec/nitro/VideoPlayerSource.nitro.ts +18 -0
- package/src/spec/nitro/VideoViewViewManager.nitro.ts +92 -0
- package/android/src/main/java/com/unifiedplayer/UnifiedPlayerModule.kt +0 -131
- package/android/src/main/java/com/unifiedplayer/UnifiedPlayerView.kt +0 -925
- package/android/src/main/java/com/unifiedplayer/UnifiedPlayerViewManager.kt +0 -69
- package/ios/UnifiedPlayerModule.h +0 -9
- package/ios/UnifiedPlayerModule.m +0 -196
- package/ios/UnifiedPlayerUIView.h +0 -70
- package/ios/UnifiedPlayerViewManager.m +0 -972
package/README.md
CHANGED
|
@@ -1,172 +1,474 @@
|
|
|
1
|
-
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="https://img.shields.io/npm/v/react-native-unified-player?style=flat-square&color=blue" alt="npm version" />
|
|
3
|
+
<img src="https://img.shields.io/npm/dm/react-native-unified-player?style=flat-square&color=green" alt="npm downloads" />
|
|
4
|
+
<img src="https://img.shields.io/badge/platforms-iOS%20%7C%20Android-lightgrey?style=flat-square" alt="platforms" />
|
|
5
|
+
<img src="https://img.shields.io/github/license/blueromans/react-native-unified-player?style=flat-square" alt="license" />
|
|
6
|
+
</p>
|
|
7
|
+
|
|
8
|
+
<h1 align="center">React Native Unified Player</h1>
|
|
9
|
+
|
|
10
|
+
<p align="center">
|
|
11
|
+
<b>A high-performance video player for React Native</b><br/>
|
|
12
|
+
Built with <a href="https://github.com/mrousavy/nitro">Nitro Modules</a> for blazing-fast native performance
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="#features">Features</a> •
|
|
17
|
+
<a href="#installation">Installation</a> •
|
|
18
|
+
<a href="#quick-start">Quick Start</a> •
|
|
19
|
+
<a href="#api-reference">API</a> •
|
|
20
|
+
<a href="#examples">Examples</a>
|
|
21
|
+
</p>
|
|
2
22
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
A React Native component for playing videos via URL, built with Fabric.
|
|
23
|
+
---
|
|
6
24
|
|
|
7
25
|
## Features
|
|
8
26
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
27
|
+
| Feature | iOS | Android |
|
|
28
|
+
|---------|:---:|:-------:|
|
|
29
|
+
| HLS / DASH Streaming | ✅ | ✅ |
|
|
30
|
+
| Local & Remote Files | ✅ | ✅ |
|
|
31
|
+
| Fullscreen Mode | ✅ | ✅ |
|
|
32
|
+
| Picture-in-Picture | ✅ | ✅ |
|
|
33
|
+
| Background Playback | ✅ | ✅ |
|
|
34
|
+
| Notification Controls | ✅ | ✅ |
|
|
35
|
+
| Subtitles / Text Tracks | ✅ | ✅ |
|
|
36
|
+
| Playback Speed Control | ✅ | ✅ |
|
|
37
|
+
| Frame Capture | ✅ | ✅ |
|
|
38
|
+
| DRM Support | 🔜 | 🔜 |
|
|
39
|
+
|
|
40
|
+
**Why Unified Player?**
|
|
41
|
+
|
|
42
|
+
- **Nitro Modules** - Direct native calls without bridge overhead
|
|
43
|
+
- **AVPlayer & ExoPlayer** - Industry-standard players under the hood
|
|
44
|
+
- **Declarative API** - Modern React hooks-based architecture
|
|
45
|
+
- **TypeScript First** - Full type safety out of the box
|
|
46
|
+
|
|
47
|
+
---
|
|
14
48
|
|
|
15
49
|
## Installation
|
|
16
50
|
|
|
17
51
|
```bash
|
|
18
|
-
|
|
52
|
+
# Using yarn
|
|
53
|
+
yarn add react-native-unified-player react-native-nitro-modules
|
|
54
|
+
|
|
55
|
+
# Using npm
|
|
56
|
+
npm install react-native-unified-player react-native-nitro-modules
|
|
19
57
|
```
|
|
20
58
|
|
|
21
|
-
|
|
59
|
+
### iOS Setup
|
|
22
60
|
|
|
23
61
|
```bash
|
|
24
|
-
|
|
62
|
+
cd ios && pod install
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Android Setup
|
|
66
|
+
|
|
67
|
+
No additional configuration required.
|
|
68
|
+
|
|
69
|
+
---
|
|
70
|
+
|
|
71
|
+
## Quick Start
|
|
72
|
+
|
|
73
|
+
```tsx
|
|
74
|
+
import React from 'react';
|
|
75
|
+
import { View, StyleSheet } from 'react-native';
|
|
76
|
+
import { UnifiedPlayerView, useVideoPlayer } from 'react-native-unified-player';
|
|
77
|
+
|
|
78
|
+
export default function App() {
|
|
79
|
+
const player = useVideoPlayer({
|
|
80
|
+
uri: 'https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4',
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
return (
|
|
84
|
+
<View style={styles.container}>
|
|
85
|
+
<UnifiedPlayerView
|
|
86
|
+
player={player}
|
|
87
|
+
style={styles.video}
|
|
88
|
+
controls
|
|
89
|
+
/>
|
|
90
|
+
</View>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const styles = StyleSheet.create({
|
|
95
|
+
container: { flex: 1, backgroundColor: '#000' },
|
|
96
|
+
video: { width: '100%', aspectRatio: 16 / 9 },
|
|
97
|
+
});
|
|
25
98
|
```
|
|
26
99
|
|
|
27
|
-
|
|
100
|
+
---
|
|
101
|
+
|
|
102
|
+
## Examples
|
|
103
|
+
|
|
104
|
+
<details>
|
|
105
|
+
<summary><b>🎮 With Playback Controls</b></summary>
|
|
28
106
|
|
|
29
|
-
|
|
107
|
+
```tsx
|
|
108
|
+
import React, { useState } from 'react';
|
|
109
|
+
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
|
|
110
|
+
import { UnifiedPlayerView, useVideoPlayer } from 'react-native-unified-player';
|
|
30
111
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
import { View } from 'react-native';
|
|
112
|
+
export default function PlayerWithControls() {
|
|
113
|
+
const [isPlaying, setIsPlaying] = useState(false);
|
|
114
|
+
const [progress, setProgress] = useState({ current: 0, duration: 0 });
|
|
35
115
|
|
|
36
|
-
const
|
|
37
|
-
|
|
116
|
+
const player = useVideoPlayer({ uri: 'https://example.com/video.mp4' }, (p) => {
|
|
117
|
+
p.loop = true;
|
|
38
118
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
const readyListener = UnifiedPlayerEvents.addListener(UnifiedPlayerEventTypes.READY, () => {
|
|
42
|
-
console.log('Player is ready to play');
|
|
43
|
-
// You can call UnifiedPlayer methods here, e.g., UnifiedPlayer.play(playerRef.current.getNativeTag());
|
|
119
|
+
p.addEventListener('onPlaybackStateChange', ({ isPlaying }) => {
|
|
120
|
+
setIsPlaying(isPlaying);
|
|
44
121
|
});
|
|
45
122
|
|
|
46
|
-
|
|
47
|
-
|
|
123
|
+
p.addEventListener('onProgress', ({ currentTime, duration }) => {
|
|
124
|
+
setProgress({ current: currentTime, duration });
|
|
48
125
|
});
|
|
126
|
+
});
|
|
49
127
|
|
|
50
|
-
|
|
128
|
+
const formatTime = (seconds: number) => {
|
|
129
|
+
const mins = Math.floor(seconds / 60);
|
|
130
|
+
const secs = Math.floor(seconds % 60);
|
|
131
|
+
return `${mins}:${secs.toString().padStart(2, '0')}`;
|
|
132
|
+
};
|
|
51
133
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
134
|
+
return (
|
|
135
|
+
<View style={styles.container}>
|
|
136
|
+
<UnifiedPlayerView player={player} style={styles.video} />
|
|
137
|
+
|
|
138
|
+
<View style={styles.controls}>
|
|
139
|
+
<TouchableOpacity onPress={() => player.seekBy(-10)}>
|
|
140
|
+
<Text style={styles.button}>-10s</Text>
|
|
141
|
+
</TouchableOpacity>
|
|
142
|
+
|
|
143
|
+
<TouchableOpacity onPress={() => isPlaying ? player.pause() : player.play()}>
|
|
144
|
+
<Text style={styles.button}>{isPlaying ? '⏸️' : '▶️'}</Text>
|
|
145
|
+
</TouchableOpacity>
|
|
146
|
+
|
|
147
|
+
<TouchableOpacity onPress={() => player.seekBy(10)}>
|
|
148
|
+
<Text style={styles.button}>+10s</Text>
|
|
149
|
+
</TouchableOpacity>
|
|
150
|
+
</View>
|
|
151
|
+
|
|
152
|
+
<Text style={styles.time}>
|
|
153
|
+
{formatTime(progress.current)} / {formatTime(progress.duration)}
|
|
154
|
+
</Text>
|
|
155
|
+
</View>
|
|
156
|
+
);
|
|
157
|
+
}
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
</details>
|
|
161
|
+
|
|
162
|
+
<details>
|
|
163
|
+
<summary><b>📺 Fullscreen Mode</b></summary>
|
|
164
|
+
|
|
165
|
+
```tsx
|
|
166
|
+
import React, { useState } from 'react';
|
|
167
|
+
import { View, Button } from 'react-native';
|
|
168
|
+
import { UnifiedPlayerView, useVideoPlayer } from 'react-native-unified-player';
|
|
169
|
+
|
|
170
|
+
export default function FullscreenExample() {
|
|
171
|
+
const [isFullscreen, setIsFullscreen] = useState(false);
|
|
172
|
+
const player = useVideoPlayer({ uri: 'https://example.com/video.mp4' });
|
|
59
173
|
|
|
60
174
|
return (
|
|
61
175
|
<View style={{ flex: 1 }}>
|
|
62
176
|
<UnifiedPlayerView
|
|
63
|
-
|
|
64
|
-
style={{ width: '100%',
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
// onProgress={(data) => console.log('View prop: Progress', data)}
|
|
177
|
+
player={player}
|
|
178
|
+
style={{ width: '100%', aspectRatio: 16 / 9 }}
|
|
179
|
+
fullscreen={isFullscreen}
|
|
180
|
+
onFullscreenChange={setIsFullscreen}
|
|
181
|
+
/>
|
|
182
|
+
|
|
183
|
+
<Button
|
|
184
|
+
title={isFullscreen ? 'Exit Fullscreen' : 'Enter Fullscreen'}
|
|
185
|
+
onPress={() => setIsFullscreen(!isFullscreen)}
|
|
73
186
|
/>
|
|
74
187
|
</View>
|
|
75
188
|
);
|
|
76
|
-
}
|
|
189
|
+
}
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
</details>
|
|
193
|
+
|
|
194
|
+
<details>
|
|
195
|
+
<summary><b>📸 Capture Video Frame</b></summary>
|
|
196
|
+
|
|
197
|
+
```tsx
|
|
198
|
+
import React, { useState } from 'react';
|
|
199
|
+
import { View, Button, Image } from 'react-native';
|
|
200
|
+
import { UnifiedPlayerView, useVideoPlayer } from 'react-native-unified-player';
|
|
201
|
+
|
|
202
|
+
export default function FrameCaptureExample() {
|
|
203
|
+
const [thumbnail, setThumbnail] = useState<string | null>(null);
|
|
204
|
+
const player = useVideoPlayer({ uri: 'https://example.com/video.mp4' });
|
|
205
|
+
|
|
206
|
+
const captureFrame = async () => {
|
|
207
|
+
try {
|
|
208
|
+
const base64 = await player.captureFrame();
|
|
209
|
+
setThumbnail(`data:image/png;base64,${base64}`);
|
|
210
|
+
} catch (error) {
|
|
211
|
+
console.error('Capture failed:', error);
|
|
212
|
+
}
|
|
213
|
+
};
|
|
77
214
|
|
|
78
|
-
|
|
215
|
+
return (
|
|
216
|
+
<View style={{ flex: 1 }}>
|
|
217
|
+
<UnifiedPlayerView
|
|
218
|
+
player={player}
|
|
219
|
+
style={{ width: '100%', aspectRatio: 16 / 9 }}
|
|
220
|
+
/>
|
|
221
|
+
|
|
222
|
+
<Button title="Capture Frame" onPress={captureFrame} />
|
|
223
|
+
|
|
224
|
+
{thumbnail && (
|
|
225
|
+
<Image
|
|
226
|
+
source={{ uri: thumbnail }}
|
|
227
|
+
style={{ width: 200, height: 112, marginTop: 20 }}
|
|
228
|
+
/>
|
|
229
|
+
)}
|
|
230
|
+
</View>
|
|
231
|
+
);
|
|
232
|
+
}
|
|
79
233
|
```
|
|
80
234
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
| Prop | Type | Required | Description |
|
|
84
|
-
|------|------|----------|-------------|
|
|
85
|
-
| `videoUrl` | `string` \| `string[]` | Yes | Video source URL or an array of URLs for a playlist. |
|
|
86
|
-
| `style` | `ViewStyle` | Yes | Apply custom styling |
|
|
87
|
-
| `autoplay` | `boolean` | No | Autoplay video when loaded |
|
|
88
|
-
| `loop` | `boolean` | No | Should the video/playlist loop when finished. **Note:** Playlist advancement and looping are handled in the JavaScript layer via the `onPlaybackComplete` callback. The native player only loops single videos based on this prop. |
|
|
89
|
-
| `onLoadStart` | `(event: { nativeEvent?: { index?: number } }) => void` | No | Callback when video begins loading. The `event.nativeEvent` may contain an `index` property on Android when playing a playlist. |
|
|
90
|
-
| `onReadyToPlay` | `() => void` | No | Callback when video is ready to play |
|
|
91
|
-
| `onError` | `(error: any) => void` | No | Callback when an error occurs |
|
|
92
|
-
| `onPlaybackComplete` | `() => void` | No | Callback when video playback finishes. Use this callback to implement playlist advancement logic in your JavaScript code. |
|
|
93
|
-
| `onProgress` | `(data: { currentTime: number; duration: number }) => void` | No | Callback for playback progress |
|
|
94
|
-
|
|
95
|
-
## Events
|
|
96
|
-
|
|
97
|
-
Events can be listened to using `UnifiedPlayerEvents.addListener(eventType, listener)`. The available event types are defined in `UnifiedPlayerEventTypes`.
|
|
98
|
-
|
|
99
|
-
- `UnifiedPlayerEventTypes.READY` ('onReadyToPlay'): Fired when the player is ready to play.
|
|
100
|
-
- `UnifiedPlayerEventTypes.ERROR` ('onError'): Fired when an error occurs.
|
|
101
|
-
- `UnifiedPlayerEventTypes.PROGRESS` ('onProgress'): Fired during playback with current time and duration (`{ currentTime: number; duration: number }`).
|
|
102
|
-
- `UnifiedPlayerEventTypes.COMPLETE` ('onPlaybackComplete'): Fired when video playback finishes.
|
|
103
|
-
- `UnifiedPlayerEventTypes.STALLED` ('onPlaybackStalled'): Fired when playback stalls.
|
|
104
|
-
- `UnifiedPlayerEventTypes.RESUMED` ('onPlaybackResumed'): Fired when playback resumes after stalling.
|
|
105
|
-
|
|
106
|
-
## Methods
|
|
107
|
-
|
|
108
|
-
Control playback using the `UnifiedPlayer` object and the native tag of the `UnifiedPlayerView` instance (obtained via `ref.current.getNativeTag()`).
|
|
109
|
-
|
|
110
|
-
- `UnifiedPlayer.play(viewTag: number)`: Starts video playback.
|
|
111
|
-
- `UnifiedPlayer.pause(viewTag: number)`: Pauses video playback.
|
|
112
|
-
- `UnifiedPlayer.seekTo(viewTag: number, time: number)`: Seeks to a specific time in seconds.
|
|
113
|
-
- `UnifiedPlayer.getCurrentTime(viewTag: number): Promise<number>`: Gets the current playback time in seconds.
|
|
114
|
-
- `UnifiedPlayer.getDuration(viewTag: number): Promise<number>`: Gets the duration of the video in seconds.
|
|
115
|
-
|
|
116
|
-
## Development
|
|
117
|
-
|
|
118
|
-
### Prerequisites
|
|
119
|
-
|
|
120
|
-
- Node.js >= 16
|
|
121
|
-
- Yarn >= 1.22
|
|
122
|
-
- React Native >= 0.79.0
|
|
123
|
-
- iOS: Xcode >= 14.0
|
|
124
|
-
- Android: Android Studio >= 2022.3
|
|
125
|
-
|
|
126
|
-
### Setup
|
|
127
|
-
|
|
128
|
-
1. Clone the repository
|
|
129
|
-
2. Install dependencies:
|
|
130
|
-
```bash
|
|
131
|
-
yarn install
|
|
132
|
-
```
|
|
133
|
-
3. Build the project:
|
|
134
|
-
```bash
|
|
135
|
-
yarn prepare
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Running the Example App
|
|
139
|
-
|
|
140
|
-
1. Navigate to the example directory:
|
|
141
|
-
```bash
|
|
142
|
-
cd example
|
|
143
|
-
```
|
|
144
|
-
2. Install dependencies:
|
|
145
|
-
```bash
|
|
146
|
-
yarn install
|
|
147
|
-
```
|
|
148
|
-
3. Run the app:
|
|
149
|
-
```bash
|
|
150
|
-
yarn ios # for iOS
|
|
151
|
-
yarn android # for Android
|
|
152
|
-
```
|
|
153
|
-
|
|
154
|
-
## Publishing
|
|
155
|
-
|
|
156
|
-
This package is automatically published to npm when changes are pushed to the `main` or `master` branch. See [PUBLISHING.md](.github/PUBLISHING.md) for setup instructions and details about npm's new authentication system (granular access tokens).
|
|
235
|
+
</details>
|
|
157
236
|
|
|
158
|
-
|
|
237
|
+
<details>
|
|
238
|
+
<summary><b>🎚️ Playback Speed Control</b></summary>
|
|
159
239
|
|
|
160
|
-
|
|
240
|
+
```tsx
|
|
241
|
+
import React, { useState } from 'react';
|
|
242
|
+
import { View, Text, TouchableOpacity, StyleSheet } from 'react-native';
|
|
243
|
+
import { UnifiedPlayerView, useVideoPlayer } from 'react-native-unified-player';
|
|
161
244
|
|
|
162
|
-
|
|
245
|
+
const SPEEDS = [0.5, 1.0, 1.25, 1.5, 2.0];
|
|
246
|
+
|
|
247
|
+
export default function SpeedControlExample() {
|
|
248
|
+
const [speed, setSpeed] = useState(1.0);
|
|
249
|
+
const player = useVideoPlayer({ uri: 'https://example.com/video.mp4' });
|
|
163
250
|
|
|
164
|
-
|
|
251
|
+
const changeSpeed = (newSpeed: number) => {
|
|
252
|
+
player.rate = newSpeed;
|
|
253
|
+
setSpeed(newSpeed);
|
|
254
|
+
};
|
|
165
255
|
|
|
166
|
-
|
|
256
|
+
return (
|
|
257
|
+
<View style={{ flex: 1 }}>
|
|
258
|
+
<UnifiedPlayerView
|
|
259
|
+
player={player}
|
|
260
|
+
style={{ width: '100%', aspectRatio: 16 / 9 }}
|
|
261
|
+
/>
|
|
262
|
+
|
|
263
|
+
<View style={styles.speedButtons}>
|
|
264
|
+
{SPEEDS.map((s) => (
|
|
265
|
+
<TouchableOpacity
|
|
266
|
+
key={s}
|
|
267
|
+
onPress={() => changeSpeed(s)}
|
|
268
|
+
style={[styles.speedBtn, speed === s && styles.activeSpeed]}
|
|
269
|
+
>
|
|
270
|
+
<Text>{s}x</Text>
|
|
271
|
+
</TouchableOpacity>
|
|
272
|
+
))}
|
|
273
|
+
</View>
|
|
274
|
+
</View>
|
|
275
|
+
);
|
|
276
|
+
}
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
</details>
|
|
280
|
+
|
|
281
|
+
<details>
|
|
282
|
+
<summary><b>📝 Subtitles / Text Tracks</b></summary>
|
|
283
|
+
|
|
284
|
+
```tsx
|
|
285
|
+
const player = useVideoPlayer({
|
|
286
|
+
uri: 'https://example.com/video.mp4',
|
|
287
|
+
externalSubtitles: [
|
|
288
|
+
{
|
|
289
|
+
label: 'English',
|
|
290
|
+
language: 'en',
|
|
291
|
+
uri: 'https://example.com/subs-en.vtt',
|
|
292
|
+
type: 'vtt',
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
label: 'Spanish',
|
|
296
|
+
language: 'es',
|
|
297
|
+
uri: 'https://example.com/subs-es.vtt',
|
|
298
|
+
type: 'vtt',
|
|
299
|
+
},
|
|
300
|
+
],
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
// Get available tracks
|
|
304
|
+
const tracks = player.getAvailableTextTracks();
|
|
305
|
+
|
|
306
|
+
// Select a track
|
|
307
|
+
player.selectTextTrack(tracks[0]);
|
|
308
|
+
|
|
309
|
+
// Disable subtitles
|
|
310
|
+
player.selectTextTrack(null);
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
</details>
|
|
314
|
+
|
|
315
|
+
---
|
|
316
|
+
|
|
317
|
+
## API Reference
|
|
318
|
+
|
|
319
|
+
### `useVideoPlayer(source, setup?)`
|
|
320
|
+
|
|
321
|
+
Creates a video player instance.
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
const player = useVideoPlayer(
|
|
325
|
+
{ uri: 'https://example.com/video.mp4' },
|
|
326
|
+
(player) => {
|
|
327
|
+
// Optional setup callback
|
|
328
|
+
player.loop = true;
|
|
329
|
+
player.volume = 0.8;
|
|
330
|
+
}
|
|
331
|
+
);
|
|
332
|
+
```
|
|
333
|
+
|
|
334
|
+
#### Source Options
|
|
335
|
+
|
|
336
|
+
| Property | Type | Description |
|
|
337
|
+
|----------|------|-------------|
|
|
338
|
+
| `uri` | `string` | Video URL (required) |
|
|
339
|
+
| `headers` | `Record<string, string>` | HTTP headers for the request |
|
|
340
|
+
| `bufferConfig` | `BufferConfig` | Buffer configuration |
|
|
341
|
+
| `externalSubtitles` | `ExternalSubtitle[]` | External subtitle tracks |
|
|
342
|
+
|
|
343
|
+
---
|
|
344
|
+
|
|
345
|
+
### `<UnifiedPlayerView />`
|
|
346
|
+
|
|
347
|
+
Video player component.
|
|
348
|
+
|
|
349
|
+
#### Props
|
|
350
|
+
|
|
351
|
+
| Prop | Type | Default | Description |
|
|
352
|
+
|------|------|---------|-------------|
|
|
353
|
+
| `player` | `VideoPlayer` | *required* | Player instance from `useVideoPlayer` |
|
|
354
|
+
| `style` | `ViewStyle` | - | View styling |
|
|
355
|
+
| `controls` | `boolean` | `false` | Show native controls |
|
|
356
|
+
| `fullscreen` | `boolean` | `false` | Fullscreen mode |
|
|
357
|
+
| `autoplay` | `boolean` | `true` | Auto-start playback |
|
|
358
|
+
| `resizeMode` | `ResizeMode` | `'none'` | `'contain'` \| `'cover'` \| `'stretch'` \| `'none'` |
|
|
359
|
+
| `pictureInPicture` | `boolean` | `false` | Enable PiP button |
|
|
360
|
+
| `autoEnterPictureInPicture` | `boolean` | `false` | Auto-enter PiP on background |
|
|
361
|
+
| `keepScreenAwake` | `boolean` | `true` | Prevent screen sleep |
|
|
362
|
+
| `surfaceType` | `SurfaceType` | `'surface'` | Android: `'surface'` \| `'texture'` |
|
|
363
|
+
|
|
364
|
+
#### Events
|
|
365
|
+
|
|
366
|
+
| Event | Callback |
|
|
367
|
+
|-------|----------|
|
|
368
|
+
| `onFullscreenChange` | `(isFullscreen: boolean) => void` |
|
|
369
|
+
| `onPictureInPictureChange` | `(isInPiP: boolean) => void` |
|
|
370
|
+
| `willEnterFullscreen` | `() => void` |
|
|
371
|
+
| `willExitFullscreen` | `() => void` |
|
|
372
|
+
| `willEnterPictureInPicture` | `() => void` |
|
|
373
|
+
| `willExitPictureInPicture` | `() => void` |
|
|
374
|
+
|
|
375
|
+
---
|
|
376
|
+
|
|
377
|
+
### VideoPlayer Instance
|
|
378
|
+
|
|
379
|
+
#### Properties
|
|
380
|
+
|
|
381
|
+
| Property | Type | Description |
|
|
382
|
+
|----------|------|-------------|
|
|
383
|
+
| `currentTime` | `number` | Current position (seconds) |
|
|
384
|
+
| `duration` | `number` | Total duration (seconds) |
|
|
385
|
+
| `volume` | `number` | Volume (0.0 - 1.0) |
|
|
386
|
+
| `muted` | `boolean` | Mute state |
|
|
387
|
+
| `rate` | `number` | Playback speed (1.0 = normal) |
|
|
388
|
+
| `loop` | `boolean` | Loop playback |
|
|
389
|
+
| `isPlaying` | `boolean` | Playing state |
|
|
390
|
+
| `status` | `VideoPlayerStatus` | `'idle'` \| `'loading'` \| `'readyToPlay'` \| `'error'` |
|
|
391
|
+
|
|
392
|
+
#### Methods
|
|
393
|
+
|
|
394
|
+
| Method | Returns | Description |
|
|
395
|
+
|--------|---------|-------------|
|
|
396
|
+
| `play()` | `void` | Start playback |
|
|
397
|
+
| `pause()` | `void` | Pause playback |
|
|
398
|
+
| `seekTo(seconds)` | `void` | Seek to position |
|
|
399
|
+
| `seekBy(seconds)` | `void` | Seek relative |
|
|
400
|
+
| `captureFrame()` | `Promise<string>` | Capture frame as base64 PNG |
|
|
401
|
+
| `getAvailableTextTracks()` | `TextTrack[]` | Get subtitle tracks |
|
|
402
|
+
| `selectTextTrack(track)` | `void` | Select subtitle track |
|
|
403
|
+
| `release()` | `void` | Release resources |
|
|
404
|
+
|
|
405
|
+
#### Events
|
|
406
|
+
|
|
407
|
+
Subscribe with `player.addEventListener(event, callback)`:
|
|
408
|
+
|
|
409
|
+
| Event | Payload |
|
|
410
|
+
|-------|---------|
|
|
411
|
+
| `onLoad` | `{ currentTime, duration, width, height, orientation }` |
|
|
412
|
+
| `onProgress` | `{ currentTime, duration, bufferDuration }` |
|
|
413
|
+
| `onPlaybackStateChange` | `{ isPlaying, isBuffering }` |
|
|
414
|
+
| `onStatusChange` | `VideoPlayerStatus` |
|
|
415
|
+
| `onEnd` | - |
|
|
416
|
+
| `onError` | `VideoRuntimeError` |
|
|
417
|
+
| `onBuffer` | `boolean` |
|
|
418
|
+
| `onSeek` | `number` |
|
|
419
|
+
| `onPlaybackRateChange` | `number` |
|
|
420
|
+
| `onVolumeChange` | `{ volume, muted }` |
|
|
421
|
+
|
|
422
|
+
---
|
|
423
|
+
|
|
424
|
+
## Requirements
|
|
425
|
+
|
|
426
|
+
| Platform | Minimum Version |
|
|
427
|
+
|----------|-----------------|
|
|
428
|
+
| React Native | 0.76.0 |
|
|
429
|
+
| iOS | 15.1 |
|
|
430
|
+
| Android | SDK 24 (Android 7.0) |
|
|
431
|
+
| Nitro Modules | 0.27.2 |
|
|
432
|
+
|
|
433
|
+
---
|
|
434
|
+
|
|
435
|
+
## Migration from v0.x
|
|
436
|
+
|
|
437
|
+
Version 1.0.0 introduces a new architecture. Here's how to migrate:
|
|
438
|
+
|
|
439
|
+
```diff
|
|
440
|
+
- import { UnifiedPlayerView, UnifiedPlayer } from 'react-native-unified-player';
|
|
441
|
+
+ import { UnifiedPlayerView, useVideoPlayer } from 'react-native-unified-player';
|
|
442
|
+
|
|
443
|
+
- const playerRef = useRef(null);
|
|
444
|
+
+ const player = useVideoPlayer({ uri: videoUrl });
|
|
445
|
+
|
|
446
|
+
- <UnifiedPlayerView
|
|
447
|
+
- ref={playerRef}
|
|
448
|
+
- videoUrl={videoUrl}
|
|
449
|
+
- onReadyToPlay={() => console.log('Ready')}
|
|
450
|
+
- />
|
|
451
|
+
+ <UnifiedPlayerView
|
|
452
|
+
+ player={player}
|
|
453
|
+
+ controls
|
|
454
|
+
+ />
|
|
455
|
+
|
|
456
|
+
- UnifiedPlayer.play(playerRef.current.getNativeTag());
|
|
457
|
+
+ player.play();
|
|
458
|
+
```
|
|
459
|
+
|
|
460
|
+
---
|
|
461
|
+
|
|
462
|
+
## Contributing
|
|
463
|
+
|
|
464
|
+
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) before submitting a PR.
|
|
465
|
+
|
|
466
|
+
## License
|
|
167
467
|
|
|
168
|
-
Yaşar Özyurt
|
|
468
|
+
MIT © [Yaşar Özyurt](https://github.com/blueromans)
|
|
169
469
|
|
|
170
470
|
---
|
|
171
471
|
|
|
172
|
-
|
|
472
|
+
<p align="center">
|
|
473
|
+
<sub>Built with ❤️ using <a href="https://github.com/mrousavy/nitro">Nitro Modules</a></sub>
|
|
474
|
+
</p>
|
package/UnifiedPlayer.podspec
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
require "json"
|
|
2
2
|
|
|
3
3
|
package = JSON.parse(File.read(File.join(__dir__, "package.json")))
|
|
4
|
+
folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
|
|
5
|
+
|
|
6
|
+
fabric_enabled = ENV['RCT_NEW_ARCH_ENABLED'] == '1'
|
|
4
7
|
|
|
5
8
|
Pod::Spec.new do |s|
|
|
6
9
|
s.name = "UnifiedPlayer"
|
|
@@ -10,18 +13,41 @@ Pod::Spec.new do |s|
|
|
|
10
13
|
s.license = package["license"]
|
|
11
14
|
s.authors = package["author"]
|
|
12
15
|
|
|
13
|
-
s.platforms = { :ios =>
|
|
16
|
+
s.platforms = { :ios => min_ios_version_supported }
|
|
14
17
|
s.source = { :git => "https://github.com/blueromans/react-native-unified-player.git", :tag => "#{s.version}" }
|
|
15
18
|
|
|
16
|
-
s.source_files =
|
|
19
|
+
s.source_files = [
|
|
20
|
+
"ios/*.{h,m,mm,swift}",
|
|
21
|
+
"ios/core/**/*.{h,m,mm,swift}",
|
|
22
|
+
"ios/hybrids/**/*.{h,m,mm,swift}",
|
|
23
|
+
"ios/view/**/*.{h,m,mm,swift}"
|
|
24
|
+
]
|
|
17
25
|
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
26
|
+
# Fabric and paper architecture-specific files have been removed
|
|
27
|
+
# They would need codegen setup to work
|
|
28
|
+
|
|
29
|
+
# Cxx to Swift bridging helpers
|
|
30
|
+
s.public_header_files = ["ios/Video-Bridging-Header.h"]
|
|
31
|
+
|
|
32
|
+
s.pod_target_xcconfig = {
|
|
33
|
+
"GCC_PREPROCESSOR_DEFINITIONS" => "$(inherited) FOLLY_NO_CONFIG FOLLY_CFG_NO_COROUTINES FOLLY_MOBILE"
|
|
34
|
+
}
|
|
25
35
|
|
|
26
|
-
#
|
|
36
|
+
# Try to manually add the dependencies
|
|
37
|
+
# because they are not automatically added by expo
|
|
38
|
+
# when USE_FRAMEWORKS is true
|
|
39
|
+
if ENV["USE_FRAMEWORKS"]
|
|
40
|
+
s.dependency "React-Core"
|
|
41
|
+
|
|
42
|
+
puts "[UnifiedPlayer] Detected USE_FRAMEWORKS, adding required dependencies..."
|
|
43
|
+
|
|
44
|
+
add_dependency(s, "React-jsinspector", :framework_name => "jsinspector_modern")
|
|
45
|
+
add_dependency(s, "React-rendererconsistency", :framework_name => "React_rendererconsistency")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Add all files generated by Nitrogen
|
|
49
|
+
load 'nitrogen/generated/ios/UnifiedPlayer+autolinking.rb'
|
|
50
|
+
add_nitrogen_files(s)
|
|
51
|
+
|
|
52
|
+
install_modules_dependencies(s)
|
|
27
53
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
|
|
2
|
+
project(UnifiedPlayer)
|
|
3
|
+
cmake_minimum_required(VERSION 3.9.0)
|
|
4
|
+
|
|
5
|
+
set (PACKAGE_NAME UnifiedPlayer)
|
|
6
|
+
set (CMAKE_VERBOSE_MAKEFILE ON)
|
|
7
|
+
set (CMAKE_CXX_STANDARD 20)
|
|
8
|
+
|
|
9
|
+
# Define C++ library and add all sources
|
|
10
|
+
add_library(${PACKAGE_NAME} SHARED
|
|
11
|
+
src/main/cpp/cpp-adapter.cpp
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
# Add Nitrogen specs :)
|
|
15
|
+
include(${CMAKE_SOURCE_DIR}/../nitrogen/generated/android/UnifiedPlayer+autolinking.cmake)
|
|
16
|
+
|
|
17
|
+
# Set up local includes
|
|
18
|
+
include_directories(
|
|
19
|
+
"src/main/cpp"
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
find_library(LOG_LIB log)
|
|
23
|
+
|
|
24
|
+
# Link all libraries together
|
|
25
|
+
target_link_libraries(
|
|
26
|
+
${PACKAGE_NAME}
|
|
27
|
+
${LOG_LIB}
|
|
28
|
+
android # <-- Android core
|
|
29
|
+
)
|