expo-video 55.0.5 → 55.0.7
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/CHANGELOG.md +30 -0
- package/android/build.gradle +2 -2
- package/android/src/main/java/expo/modules/video/FullscreenPlayerActivity.kt +16 -12
- package/android/src/main/java/expo/modules/video/PlayerViewExtension.kt +51 -0
- package/android/src/main/java/expo/modules/video/VideoModule.kt +8 -8
- package/android/src/main/java/expo/modules/video/VideoView.kt +26 -4
- package/android/src/main/java/expo/modules/video/player/FirstFrameEventGenerator.kt +5 -7
- package/android/src/main/java/expo/modules/video/player/VideoPlayer.kt +42 -12
- package/android/src/main/java/expo/modules/video/records/ButtonOptions.kt +15 -0
- package/android/src/main/java/expo/modules/video/records/PlayerBuilderOptions.kt +13 -0
- package/android/src/main/java/expo/modules/video/records/Tracks.kt +26 -5
- package/build/VideoPlayer.d.ts +6 -4
- package/build/VideoPlayer.d.ts.map +1 -1
- package/build/VideoPlayer.js +9 -6
- package/build/VideoPlayer.js.map +1 -1
- package/build/VideoPlayer.types.d.ts +60 -1
- package/build/VideoPlayer.types.d.ts.map +1 -1
- package/build/VideoPlayer.types.js.map +1 -1
- package/build/VideoView.types.d.ts +61 -0
- package/build/VideoView.types.d.ts.map +1 -1
- package/build/VideoView.types.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/expo-module.config.json +1 -1
- package/ios/Cache/CachedResource.swift +74 -7
- package/ios/Cache/CachingHelpers.swift +24 -9
- package/ios/Cache/MediaFileHandle.swift +54 -9
- package/ios/Cache/MediaInfo.swift +65 -22
- package/ios/Cache/ResourceLoaderDelegate.swift +38 -6
- package/ios/Cache/VideoCacheManager.swift +1 -1
- package/ios/NowPlayingManager.swift +2 -2
- package/ios/Records/Tracks.swift +66 -85
- package/ios/Utils/AVAssetVariant+VideoTracks.swift +17 -0
- package/ios/Utils/AvAssetTrack+VideoTracks.swift +52 -0
- package/ios/Utils/FourCharCode+toString.swift +25 -0
- package/ios/Utils/HlsUriUtils.swift +27 -0
- package/ios/VideoAsset.swift +7 -7
- package/ios/VideoManager.swift +2 -2
- package/ios/VideoModule.swift +1 -1
- package/ios/VideoPlayerAudioTracks.swift +2 -2
- package/ios/VideoPlayerItem.swift +55 -18
- package/ios/VideoPlayerObserver.swift +1 -12
- package/ios/VideoPlayerSubtitles.swift +2 -2
- package/local-maven-repo/host/exp/exponent/expo.modules.video/{55.0.5/expo.modules.video-55.0.5-sources.jar → 55.0.7/expo.modules.video-55.0.7-sources.jar} +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7-sources.jar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7-sources.jar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7-sources.jar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7-sources.jar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.aar.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.aar.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.aar.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.aar.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/{55.0.5/expo.modules.video-55.0.5.module → 55.0.7/expo.modules.video-55.0.7.module} +22 -22
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.module.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.module.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.module.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.module.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/{55.0.5/expo.modules.video-55.0.5.pom → 55.0.7/expo.modules.video-55.0.7.pom} +13 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.pom.md5 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.pom.sha1 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.pom.sha256 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.7/expo.modules.video-55.0.7.pom.sha512 +1 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml +4 -4
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.md5 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha1 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha256 +1 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/maven-metadata.xml.sha512 +1 -1
- package/package.json +2 -2
- package/src/VideoPlayer.tsx +14 -7
- package/src/VideoPlayer.types.ts +73 -1
- package/src/VideoView.types.ts +63 -0
- package/src/index.ts +6 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5-sources.jar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5-sources.jar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5-sources.jar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5-sources.jar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.aar +0 -0
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.aar.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.aar.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.aar.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.aar.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.module.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.module.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.module.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.module.sha512 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.pom.md5 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.pom.sha1 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.pom.sha256 +0 -1
- package/local-maven-repo/host/exp/exponent/expo.modules.video/55.0.5/expo.modules.video-55.0.5.pom.sha512 +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -10,12 +10,40 @@
|
|
|
10
10
|
|
|
11
11
|
### 💡 Others
|
|
12
12
|
|
|
13
|
+
## 55.0.7 — 2026-02-20
|
|
14
|
+
|
|
15
|
+
### 🎉 New features
|
|
16
|
+
|
|
17
|
+
- [Android][iOS] Add `url` field to HLS video tracks. ([#41681](https://github.com/expo/expo/pull/41681) by [@behenate](https://github.com/behenate))
|
|
18
|
+
- [Android][iOS] Add `name`, `isDefault` and `autoSelect` fields to `AudioTrack` and `SubtitleTrack`. ([#43250](https://github.com/expo/expo/pull/43250) by [@behenate](https://github.com/behenate))
|
|
19
|
+
|
|
20
|
+
### 💡 Others
|
|
21
|
+
|
|
22
|
+
- Update HLS video track fetching for iOS 26+. ([#41681](https://github.com/expo/expo/pull/41681) by [@behenate](https://github.com/behenate))
|
|
23
|
+
|
|
24
|
+
## 55.0.6 — 2026-02-16
|
|
25
|
+
|
|
26
|
+
### 🛠 Breaking changes
|
|
27
|
+
|
|
28
|
+
- [Android] The next and previous buttons are now hidden by default in the native `VideoView` controls. ([#42875](https://github.com/expo/expo/pull/42875) by [@behenate](https://github.com/behenate))
|
|
29
|
+
|
|
30
|
+
### 🎉 New features
|
|
31
|
+
|
|
32
|
+
- [Android] Add `buttonConfiguration` prop to `VideoView`. ([#42875](https://github.com/expo/expo/pull/42875) by [@behenate](https://github.com/behenate))
|
|
33
|
+
- [Android] Add `PlayerBuilderOptions` parameter to `useVideoPlayer` hook to configure seek backward/forward increments. ([#43043](https://github.com/expo/expo/pull/43043) by [@behenate](https://github.com/behenate))
|
|
34
|
+
|
|
35
|
+
### 🐛 Bug fixes
|
|
36
|
+
|
|
37
|
+
- [Android] Fix only one player getting released when reloading with multiple players present. ([#42780](https://github.com/expo/expo/pull/42780) by [@behenate](https://github.com/behenate))
|
|
38
|
+
- [iOS] Fix data getting corrupted when caching is enabled. ([#42621](https://github.com/expo/expo/pull/42621) by [@behenate](https://github.com/behenate))
|
|
39
|
+
|
|
13
40
|
## 55.0.5 — 2026-02-08
|
|
14
41
|
|
|
15
42
|
### 🐛 Bug fixes
|
|
16
43
|
|
|
17
44
|
- [iOS] Prevents blocking main thread when loading asset tracks for non-HSL tracks ([#42037](https://github.com/expo/expo/pull/42037) by [@santitopo](https://github.com/santitopo))
|
|
18
45
|
- [Android] Fix crash due to `SimpleCache` directory lock conflicts. ([#42723](https://github.com/expo/expo/pull/42723) by [@santitopo](https://github.com/santitopo))
|
|
46
|
+
- [Android] Avoid crash when FullscreenPlayerActivity init fails. ([#42943](https://github.com/expo/expo/pull/42943) by [@amyu](https://github.com/amyu))
|
|
19
47
|
|
|
20
48
|
## 55.0.4 — 2026-02-03
|
|
21
49
|
|
|
@@ -46,6 +74,7 @@ _This version does not introduce any user-facing changes._
|
|
|
46
74
|
- [Android][iOS] Add `seek tolerance` and `scrubbingModeOptions` properties to the player. ([#40203](https://github.com/expo/expo/pull/40203) by [@behenate](https://github.com/behenate))
|
|
47
75
|
- Allow assigning `null` value to the `player` prop of the `VideoView` ([#40860](https://github.com/expo/expo/pull/40860) by [@behenate](https://github.com/behenate))
|
|
48
76
|
- [Android][iOS] Add `averageBitrate` and `peakBitrate` for video tracks. ([#41532](https://github.com/expo/expo/pull/41532) by [@behenate](https://github.com/behenate))
|
|
77
|
+
- [Android][iOS] Add `url` field to HLS video tracks. ([#41681](https://github.com/expo/expo/pull/41681) by [@behenate](https://github.com/behenate))
|
|
49
78
|
|
|
50
79
|
### 🐛 Bug fixes
|
|
51
80
|
|
|
@@ -65,6 +94,7 @@ _This version does not introduce any user-facing changes._
|
|
|
65
94
|
- Add extract the object `VideoSource` type into separate `VideoSourceObject` type. ([#41514](https://github.com/expo/expo/pull/41514) by [@behenate](https://github.com/behenate))
|
|
66
95
|
- [Android] Set property values on calling thread. ([#41533](https://github.com/expo/expo/pull/41533) by [@behenate](https://github.com/behenate))
|
|
67
96
|
- Mark the video track `bitrate` field as deprecated. ([#41532](https://github.com/expo/expo/pull/41532) by [@behenate](https://github.com/behenate))
|
|
97
|
+
- Update HLS video track fetching for iOS 26+. ([#41681](https://github.com/expo/expo/pull/41681) by [@behenate](https://github.com/behenate))
|
|
68
98
|
|
|
69
99
|
## 3.0.15 - 2025-12-05
|
|
70
100
|
|
package/android/build.gradle
CHANGED
|
@@ -27,14 +27,14 @@ import expo.modules.video.managers.VideoManager
|
|
|
27
27
|
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
|
28
28
|
class FullscreenPlayerActivity : Activity() {
|
|
29
29
|
private lateinit var mContentView: View
|
|
30
|
-
private
|
|
30
|
+
private var videoViewId: String? = null
|
|
31
31
|
private var videoPlayer: VideoPlayer? = null
|
|
32
32
|
private lateinit var playerView: PlayerView
|
|
33
33
|
private lateinit var videoView: VideoView
|
|
34
34
|
private var didFinish = false
|
|
35
35
|
private var wasAutoPaused = false
|
|
36
36
|
private lateinit var options: FullscreenOptions
|
|
37
|
-
private
|
|
37
|
+
private var orientationHelper: FullscreenActivityOrientationHelper? = null
|
|
38
38
|
private var captioningChangeListener: CaptioningManager.CaptioningChangeListener? = null
|
|
39
39
|
|
|
40
40
|
override fun onCreate(savedInstanceState: Bundle?) {
|
|
@@ -53,7 +53,8 @@ class FullscreenPlayerActivity : Activity() {
|
|
|
53
53
|
?: throw FullScreenOptionsNotFoundException()
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
-
videoView = VideoManager.getVideoView(
|
|
56
|
+
videoView = videoViewId?.let { VideoManager.getVideoView(it) }
|
|
57
|
+
?: throw FullScreenVideoViewNotFoundException()
|
|
57
58
|
|
|
58
59
|
orientationHelper = FullscreenActivityOrientationHelper(
|
|
59
60
|
this,
|
|
@@ -65,7 +66,7 @@ class FullscreenPlayerActivity : Activity() {
|
|
|
65
66
|
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED
|
|
66
67
|
}
|
|
67
68
|
)
|
|
68
|
-
orientationHelper
|
|
69
|
+
orientationHelper?.startOrientationEventListener()
|
|
69
70
|
} catch (e: CodedException) {
|
|
70
71
|
Log.e("ExpoVideo", "${e.message}", e)
|
|
71
72
|
finish()
|
|
@@ -94,13 +95,16 @@ class FullscreenPlayerActivity : Activity() {
|
|
|
94
95
|
super.onPostCreate(savedInstanceState)
|
|
95
96
|
hideStatusBar()
|
|
96
97
|
setupFullscreenButton()
|
|
97
|
-
|
|
98
|
+
val requiresLinearPlayback = videoPlayer?.requiresLinearPlayback ?: false
|
|
99
|
+
val buttonConfig = videoView.buttonOptions.copy(showBottomBar = true) // Always show bottom bar in fullscreen mode so user can exit
|
|
100
|
+
playerView.applyButtonOptions(buttonConfig, requiresLinearPlayback)
|
|
101
|
+
playerView.setTimeBarInteractive(requiresLinearPlayback)
|
|
98
102
|
playerView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ ->
|
|
99
103
|
// On every re-layout ExoPlayer makes the timeBar interactive.
|
|
100
104
|
// We need to disable it to keep scrubbing off.
|
|
101
|
-
playerView.setTimeBarInteractive(
|
|
105
|
+
playerView.setTimeBarInteractive(requiresLinearPlayback)
|
|
102
106
|
}
|
|
103
|
-
playerView.setShowSubtitleButton(videoView.
|
|
107
|
+
playerView.setShowSubtitleButton(videoView.buttonOptions.showSubtitles ?: videoView.currentTrackHasSubtitles)
|
|
104
108
|
|
|
105
109
|
// Configure subtitle view to fix sizing issues with embedded styles (same as VideoView)
|
|
106
110
|
SubtitleUtils.configureSubtitleView(playerView, this)
|
|
@@ -116,7 +120,7 @@ class FullscreenPlayerActivity : Activity() {
|
|
|
116
120
|
override fun finish() {
|
|
117
121
|
super.finish()
|
|
118
122
|
didFinish = true
|
|
119
|
-
VideoManager.getVideoView(
|
|
123
|
+
videoViewId?.let { VideoManager.getVideoView(it).attachPlayer() }
|
|
120
124
|
|
|
121
125
|
// Disable the exit transition
|
|
122
126
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
|
@@ -128,7 +132,7 @@ class FullscreenPlayerActivity : Activity() {
|
|
|
128
132
|
}
|
|
129
133
|
|
|
130
134
|
override fun onResume() {
|
|
131
|
-
orientationHelper
|
|
135
|
+
orientationHelper?.startOrientationEventListener()
|
|
132
136
|
playerView.useController = true
|
|
133
137
|
// Reconfigure subtitles when resuming (handles returning from settings)
|
|
134
138
|
SubtitleUtils.configureSubtitleView(playerView, this)
|
|
@@ -143,7 +147,7 @@ class FullscreenPlayerActivity : Activity() {
|
|
|
143
147
|
videoPlayer?.player?.pause()
|
|
144
148
|
}
|
|
145
149
|
}
|
|
146
|
-
orientationHelper
|
|
150
|
+
orientationHelper?.stopOrientationEventListener()
|
|
147
151
|
super.onPause()
|
|
148
152
|
}
|
|
149
153
|
|
|
@@ -159,7 +163,7 @@ class FullscreenPlayerActivity : Activity() {
|
|
|
159
163
|
|
|
160
164
|
videoView.exitFullscreen()
|
|
161
165
|
VideoManager.unregisterFullscreenPlayerActivity(hashCode().toString())
|
|
162
|
-
orientationHelper
|
|
166
|
+
orientationHelper?.stopOrientationEventListener()
|
|
163
167
|
}
|
|
164
168
|
|
|
165
169
|
private fun setupFullscreenButton() {
|
|
@@ -213,7 +217,7 @@ class FullscreenPlayerActivity : Activity() {
|
|
|
213
217
|
|
|
214
218
|
override fun onConfigurationChanged(newConfig: Configuration) {
|
|
215
219
|
super.onConfigurationChanged(newConfig)
|
|
216
|
-
orientationHelper
|
|
220
|
+
orientationHelper?.onConfigurationChanged(newConfig)
|
|
217
221
|
}
|
|
218
222
|
|
|
219
223
|
companion object {
|
|
@@ -34,3 +34,54 @@ internal fun PlayerView.setFullscreenButtonVisibility(visible: Boolean) {
|
|
|
34
34
|
android.view.View.GONE
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
|
39
|
+
internal fun PlayerView.setSettingsButtonVisibility(visible: Boolean) {
|
|
40
|
+
val settingsButton = findViewById<android.widget.ImageButton>(androidx.media3.ui.R.id.exo_settings)
|
|
41
|
+
settingsButton?.visibility = if (visible) {
|
|
42
|
+
android.view.View.VISIBLE
|
|
43
|
+
} else {
|
|
44
|
+
android.view.View.GONE
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
|
49
|
+
internal fun PlayerView.setPlayPauseButtonVisibility(visible: Boolean) {
|
|
50
|
+
val playPauseButton = findViewById<android.widget.ImageButton>(androidx.media3.ui.R.id.exo_play_pause)
|
|
51
|
+
playPauseButton?.visibility = if (visible) {
|
|
52
|
+
android.view.View.VISIBLE
|
|
53
|
+
} else {
|
|
54
|
+
android.view.View.GONE
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
|
59
|
+
internal fun PlayerView.setBottomBarVisibility(visible: Boolean) {
|
|
60
|
+
val bottomBar = findViewById<android.view.ViewGroup>(androidx.media3.ui.R.id.exo_bottom_bar)
|
|
61
|
+
bottomBar?.visibility = if (visible) {
|
|
62
|
+
android.view.View.VISIBLE
|
|
63
|
+
} else {
|
|
64
|
+
android.view.View.GONE
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
val progressBar = findViewById<DefaultTimeBar>(androidx.media3.ui.R.id.exo_progress)
|
|
68
|
+
progressBar?.visibility = if (visible) {
|
|
69
|
+
android.view.View.VISIBLE
|
|
70
|
+
} else {
|
|
71
|
+
android.view.View.GONE
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@androidx.annotation.OptIn(androidx.media3.common.util.UnstableApi::class)
|
|
76
|
+
internal fun PlayerView.applyButtonOptions(
|
|
77
|
+
config: expo.modules.video.records.ButtonOptions,
|
|
78
|
+
requiresLinearPlayback: Boolean = false
|
|
79
|
+
) {
|
|
80
|
+
setShowFastForwardButton(!requiresLinearPlayback && config.showSeekForward)
|
|
81
|
+
setShowRewindButton(!requiresLinearPlayback && config.showSeekBackward)
|
|
82
|
+
setShowPreviousButton(!requiresLinearPlayback && config.showPrevious)
|
|
83
|
+
setShowNextButton(!requiresLinearPlayback && config.showNext)
|
|
84
|
+
setSettingsButtonVisibility(config.showSettings)
|
|
85
|
+
setPlayPauseButtonVisibility(config.showPlayPause)
|
|
86
|
+
setBottomBarVisibility(config.showBottomBar)
|
|
87
|
+
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
@file:OptIn(EitherType::class)
|
|
2
|
-
|
|
3
1
|
package expo.modules.video
|
|
4
2
|
|
|
5
3
|
import android.net.Uri
|
|
@@ -8,7 +6,6 @@ import androidx.media3.common.Player.REPEAT_MODE_OFF
|
|
|
8
6
|
import androidx.media3.common.Player.REPEAT_MODE_ONE
|
|
9
7
|
import androidx.media3.common.util.UnstableApi
|
|
10
8
|
import expo.modules.kotlin.Promise
|
|
11
|
-
import expo.modules.kotlin.apifeatures.EitherType
|
|
12
9
|
import expo.modules.kotlin.functions.Coroutine
|
|
13
10
|
import expo.modules.kotlin.functions.Queues
|
|
14
11
|
import expo.modules.kotlin.modules.Module
|
|
@@ -19,6 +16,8 @@ import expo.modules.video.enums.AudioMixingMode
|
|
|
19
16
|
import expo.modules.video.enums.ContentFit
|
|
20
17
|
import expo.modules.video.player.VideoPlayer
|
|
21
18
|
import expo.modules.video.records.BufferOptions
|
|
19
|
+
import expo.modules.video.records.PlayerBuilderOptions
|
|
20
|
+
import expo.modules.video.records.ButtonOptions
|
|
22
21
|
import expo.modules.video.records.FullscreenOptions
|
|
23
22
|
import expo.modules.video.records.SubtitleTrack
|
|
24
23
|
import expo.modules.video.records.AudioTrack
|
|
@@ -72,8 +71,8 @@ class VideoModule : Module() {
|
|
|
72
71
|
}
|
|
73
72
|
|
|
74
73
|
Class(VideoPlayer::class) {
|
|
75
|
-
Constructor { source: VideoSource? ->
|
|
76
|
-
val player = VideoPlayer(appContext.throwingActivity.applicationContext, appContext, source)
|
|
74
|
+
Constructor { source: VideoSource?, /* useSynchronousReplace - iOS-only */ _: Boolean?, playerBuilderOptions: PlayerBuilderOptions? ->
|
|
75
|
+
val player = VideoPlayer(appContext.throwingActivity.applicationContext, appContext, source, playerBuilderOptions)
|
|
77
76
|
appContext.mainQueue.launch {
|
|
78
77
|
player.prepare()
|
|
79
78
|
}
|
|
@@ -410,9 +409,10 @@ private inline fun <reified T : VideoView> ViewDefinitionBuilder<T>.VideoViewCom
|
|
|
410
409
|
}
|
|
411
410
|
}
|
|
412
411
|
Prop("requiresLinearPlayback") { view: T, requiresLinearPlayback: Boolean? ->
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
412
|
+
view.requiresLinearPlayback = requiresLinearPlayback ?: false
|
|
413
|
+
}
|
|
414
|
+
Prop("buttonOptions") { view: T, buttonOptions: ButtonOptions? ->
|
|
415
|
+
view.buttonOptions = buttonOptions ?: ButtonOptions()
|
|
416
416
|
}
|
|
417
417
|
Prop("useExoShutter") { view: T, useExoShutter: Boolean? ->
|
|
418
418
|
view.useExoShutter = useExoShutter
|
|
@@ -26,6 +26,7 @@ import expo.modules.video.player.VideoPlayer
|
|
|
26
26
|
import expo.modules.video.listeners.VideoPlayerListener
|
|
27
27
|
import expo.modules.video.listeners.VideoViewListener
|
|
28
28
|
import expo.modules.video.records.AudioTrack
|
|
29
|
+
import expo.modules.video.records.ButtonOptions
|
|
29
30
|
import expo.modules.video.records.SubtitleTrack
|
|
30
31
|
import expo.modules.video.records.VideoSource
|
|
31
32
|
import expo.modules.video.records.VideoTrack
|
|
@@ -57,11 +58,25 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
57
58
|
var wasAutoPaused: Boolean = false
|
|
58
59
|
var isInFullscreen: Boolean = false
|
|
59
60
|
private set
|
|
60
|
-
var
|
|
61
|
+
var currentTrackHasSubtitles = false
|
|
61
62
|
private set
|
|
62
63
|
var showsAudioTracksButton = false
|
|
63
64
|
private set
|
|
64
65
|
|
|
66
|
+
var requiresLinearPlayback: Boolean = false
|
|
67
|
+
set(value) {
|
|
68
|
+
field = value
|
|
69
|
+
videoPlayer?.requiresLinearPlayback = value
|
|
70
|
+
playerView.applyRequiresLinearPlayback(value)
|
|
71
|
+
applyButtonSettings()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
var buttonOptions: ButtonOptions = ButtonOptions()
|
|
75
|
+
set(value) {
|
|
76
|
+
field = value
|
|
77
|
+
applyButtonSettings()
|
|
78
|
+
}
|
|
79
|
+
|
|
65
80
|
private var listeners = mutableListOf<WeakReference<VideoViewListener>>()
|
|
66
81
|
private val currentActivity = appContext.throwingActivity
|
|
67
82
|
private val decorView = currentActivity.window.decorView
|
|
@@ -131,8 +146,9 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
131
146
|
|
|
132
147
|
var useNativeControls: Boolean = true
|
|
133
148
|
set(value) {
|
|
149
|
+
val shouldShowSubtitle = value && (buttonOptions.showSubtitles ?: currentTrackHasSubtitles)
|
|
134
150
|
playerView.useController = value
|
|
135
|
-
playerView.setShowSubtitleButton(
|
|
151
|
+
playerView.setShowSubtitleButton(shouldShowSubtitle)
|
|
136
152
|
field = value
|
|
137
153
|
}
|
|
138
154
|
|
|
@@ -291,9 +307,9 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
291
307
|
}
|
|
292
308
|
|
|
293
309
|
override fun onTracksChanged(player: VideoPlayer, tracks: Tracks) {
|
|
294
|
-
|
|
310
|
+
currentTrackHasSubtitles = player.subtitles.availableSubtitleTracks.isNotEmpty()
|
|
295
311
|
showsAudioTracksButton = player.audioTracks.availableAudioTracks.size > 1
|
|
296
|
-
playerView.setShowSubtitleButton(
|
|
312
|
+
playerView.setShowSubtitleButton(buttonOptions.showSubtitles ?: currentTrackHasSubtitles)
|
|
297
313
|
super.onTracksChanged(player, tracks)
|
|
298
314
|
}
|
|
299
315
|
|
|
@@ -407,6 +423,12 @@ open class VideoView(context: Context, appContext: AppContext, useTextureView: B
|
|
|
407
423
|
}
|
|
408
424
|
}
|
|
409
425
|
|
|
426
|
+
private fun applyButtonSettings() {
|
|
427
|
+
val shouldShowSubtitle = buttonOptions.showSubtitles ?: currentTrackHasSubtitles
|
|
428
|
+
playerView.applyButtonOptions(buttonOptions, requiresLinearPlayback)
|
|
429
|
+
playerView.setShowSubtitleButton(shouldShowSubtitle)
|
|
430
|
+
}
|
|
431
|
+
|
|
410
432
|
companion object {
|
|
411
433
|
fun isPictureInPictureSupported(currentActivity: Activity): Boolean {
|
|
412
434
|
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && currentActivity.packageManager.hasSystemFeature(
|
|
@@ -28,10 +28,9 @@ internal class FirstFrameEventGenerator(
|
|
|
28
28
|
appContext: AppContext,
|
|
29
29
|
videoPlayer: VideoPlayer,
|
|
30
30
|
private val currentViewReference: MutableWeakReference<VideoView?>,
|
|
31
|
-
private
|
|
31
|
+
private var onFirstFrameRendered: (() -> Unit)?
|
|
32
32
|
) : Player.Listener, VideoPlayerListener {
|
|
33
33
|
private val videoPlayerReference = WeakReference(videoPlayer)
|
|
34
|
-
private val weakAppContext = WeakReference(appContext)
|
|
35
34
|
private var hasPendingOnFirstFrame = false
|
|
36
35
|
internal var hasSentFirstFrameForCurrentMediaItem = false
|
|
37
36
|
private set
|
|
@@ -45,12 +44,11 @@ internal class FirstFrameEventGenerator(
|
|
|
45
44
|
}
|
|
46
45
|
}
|
|
47
46
|
|
|
47
|
+
@MainThread
|
|
48
48
|
fun release() {
|
|
49
49
|
videoPlayerReference.get()?.removeListener(this)
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
videoPlayerReference.get()?.player?.removeListener(this@FirstFrameEventGenerator)
|
|
53
|
-
}
|
|
50
|
+
videoPlayerReference.get()?.player?.removeListener(this)
|
|
51
|
+
onFirstFrameRendered = null
|
|
54
52
|
}
|
|
55
53
|
|
|
56
54
|
override fun onRenderedFirstFrame() {
|
|
@@ -80,7 +78,7 @@ internal class FirstFrameEventGenerator(
|
|
|
80
78
|
// We want to match the behavior across platforms, so we limit the number of event emissions.
|
|
81
79
|
private fun maybeCallOnFirstFrameRendered() {
|
|
82
80
|
if (!hasSentFirstFrameForCurrentMediaItem || !hasSentFirstFrameForCurrentVideoView) {
|
|
83
|
-
onFirstFrameRendered()
|
|
81
|
+
onFirstFrameRendered?.invoke()
|
|
84
82
|
}
|
|
85
83
|
hasPendingOnFirstFrame = false
|
|
86
84
|
hasSentFirstFrameForCurrentMediaItem = true
|
|
@@ -20,6 +20,7 @@ import androidx.media3.exoplayer.DecoderReuseEvaluation
|
|
|
20
20
|
import androidx.media3.exoplayer.DefaultRenderersFactory
|
|
21
21
|
import androidx.media3.exoplayer.ExoPlayer
|
|
22
22
|
import androidx.media3.exoplayer.analytics.AnalyticsListener
|
|
23
|
+
import androidx.media3.exoplayer.hls.HlsManifest
|
|
23
24
|
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
|
24
25
|
import androidx.media3.session.MediaSession
|
|
25
26
|
import androidx.media3.ui.PlayerView
|
|
@@ -47,13 +48,17 @@ import expo.modules.video.records.VideoSource
|
|
|
47
48
|
import expo.modules.video.utils.MutableWeakReference
|
|
48
49
|
import expo.modules.video.records.VideoTrack
|
|
49
50
|
import expo.modules.video.utils.buildBasicMediaSession
|
|
51
|
+
import kotlinx.coroutines.DelicateCoroutinesApi
|
|
52
|
+
import kotlinx.coroutines.Dispatchers
|
|
53
|
+
import kotlinx.coroutines.GlobalScope
|
|
50
54
|
import kotlinx.coroutines.launch
|
|
51
55
|
import java.io.FileInputStream
|
|
52
56
|
import java.lang.ref.WeakReference
|
|
57
|
+
import kotlin.time.DurationUnit
|
|
53
58
|
|
|
54
59
|
// https://developer.android.com/guide/topics/media/media3/getting-started/migration-guide#improvements_in_media3
|
|
55
60
|
@UnstableApi
|
|
56
|
-
class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSource?) : AutoCloseable, SharedObject(appContext), IntervalUpdateEmitter {
|
|
61
|
+
class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSource?, playerBuilderOptions: expo.modules.video.records.PlayerBuilderOptions? = null) : AutoCloseable, SharedObject(appContext), IntervalUpdateEmitter {
|
|
57
62
|
// This improves the performance of playing DRM-protected content
|
|
58
63
|
private var renderersFactory = DefaultRenderersFactory(context)
|
|
59
64
|
.forceEnableMediaCodecAsynchronousQueueing()
|
|
@@ -70,9 +75,16 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
|
|
70
75
|
|
|
71
76
|
val player = ExoPlayer
|
|
72
77
|
.Builder(context, renderersFactory)
|
|
73
|
-
.
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
.apply {
|
|
79
|
+
setLooper(context.mainLooper)
|
|
80
|
+
setLoadControl(loadControl)
|
|
81
|
+
playerBuilderOptions?.seekBackwardIncrement?.let {
|
|
82
|
+
setSeekBackIncrementMs((it).toLong(DurationUnit.MILLISECONDS).coerceIn(1, 999_000))
|
|
83
|
+
}
|
|
84
|
+
playerBuilderOptions?.seekForwardIncrement?.let {
|
|
85
|
+
setSeekForwardIncrementMs((it).toLong(DurationUnit.MILLISECONDS).coerceIn(1, 999_000))
|
|
86
|
+
}
|
|
87
|
+
}.build()
|
|
76
88
|
|
|
77
89
|
internal val firstFrameEventGenerator: FirstFrameEventGenerator
|
|
78
90
|
val serviceConnection = PlaybackServiceConnection(WeakReference(this), appContext)
|
|
@@ -238,7 +250,8 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
|
|
238
250
|
val newAudioTracks = audioTracks.availableAudioTracks
|
|
239
251
|
val newCurrentSubtitleTrack = subtitles.currentSubtitleTrack
|
|
240
252
|
val newCurrentAudioTrack = audioTracks.currentAudioTrack
|
|
241
|
-
|
|
253
|
+
val hlsManifest = player.currentManifest as? HlsManifest
|
|
254
|
+
availableVideoTracks = tracks.toVideoTracks(hlsManifest)
|
|
242
255
|
refreshPlaybackInfo()
|
|
243
256
|
|
|
244
257
|
if (isLoadingNewSource) {
|
|
@@ -346,7 +359,17 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
|
|
346
359
|
}
|
|
347
360
|
}
|
|
348
361
|
|
|
362
|
+
@kotlin.OptIn(DelicateCoroutinesApi::class)
|
|
349
363
|
override fun close() {
|
|
364
|
+
// Releases the listeners from VideoPlayerKeepAwake
|
|
365
|
+
keepScreenOnWhilePlaying = false
|
|
366
|
+
|
|
367
|
+
intervalUpdateClock.interval = 0L
|
|
368
|
+
|
|
369
|
+
synchronized(listeners) {
|
|
370
|
+
listeners.clear()
|
|
371
|
+
}
|
|
372
|
+
|
|
350
373
|
if (serviceConnection.isConnected) {
|
|
351
374
|
appContext?.reactContext?.unbindService(serviceConnection)
|
|
352
375
|
}
|
|
@@ -355,19 +378,20 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
|
|
355
378
|
|
|
356
379
|
VideoManager.unregisterVideoPlayer(this@VideoPlayer)
|
|
357
380
|
|
|
358
|
-
appContext
|
|
381
|
+
// Run on global scope (not appContext.mainQueue) so that reloading doesn't cancel the release process
|
|
382
|
+
// https://github.com/expo/expo/blob/cdf592a7fea56fc01b0149e9b2e5dbd294bcdc4c/packages/expo-modules-core/android/src/main/java/expo/modules/kotlin/AppContext.kt#L277-L279
|
|
383
|
+
GlobalScope.launch(Dispatchers.Main) {
|
|
359
384
|
firstFrameEventGenerator.release()
|
|
360
385
|
player.removeListener(playerListener)
|
|
386
|
+
player.removeAnalyticsListener(analyticsListener)
|
|
361
387
|
player.release()
|
|
362
388
|
}
|
|
363
389
|
uncommittedSource = null
|
|
364
390
|
commitedSource = null
|
|
365
|
-
// Releases the listeners from VideoPlayerKeepAwake
|
|
366
|
-
keepScreenOnWhilePlaying = false
|
|
367
391
|
}
|
|
368
392
|
|
|
369
|
-
override fun
|
|
370
|
-
super.
|
|
393
|
+
override fun sharedObjectDidRelease() {
|
|
394
|
+
super.sharedObjectDidRelease()
|
|
371
395
|
close()
|
|
372
396
|
}
|
|
373
397
|
|
|
@@ -548,17 +572,23 @@ class VideoPlayer(val context: Context, appContext: AppContext, source: VideoSou
|
|
|
548
572
|
// Extension functions
|
|
549
573
|
|
|
550
574
|
@OptIn(UnstableApi::class)
|
|
551
|
-
private fun Tracks.toVideoTracks(): List<VideoTrack> {
|
|
575
|
+
private fun Tracks.toVideoTracks(sourceManifest: HlsManifest?): List<VideoTrack> {
|
|
552
576
|
val videoTracks = mutableListOf<VideoTrack?>()
|
|
553
577
|
for (group in this.groups) {
|
|
554
578
|
for (i in 0 until group.length) {
|
|
555
579
|
val format = group.getTrackFormat(i)
|
|
556
580
|
val isSupported = group.isTrackSupported(i)
|
|
581
|
+
val hlsVariant = sourceManifest?.multivariantPlaylist?.variants?.firstOrNull {
|
|
582
|
+
it.format.id == format.id
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
// We provide the variant url only for HLS sources
|
|
586
|
+
val variantUrl = hlsVariant?.url
|
|
557
587
|
|
|
558
588
|
if (!MimeTypes.isVideo(format.sampleMimeType)) {
|
|
559
589
|
continue
|
|
560
590
|
}
|
|
561
|
-
videoTracks.add(VideoTrack.fromFormat(format, isSupported))
|
|
591
|
+
videoTracks.add(VideoTrack.fromFormat(format, isSupported, variantUrl))
|
|
562
592
|
}
|
|
563
593
|
}
|
|
564
594
|
return videoTracks.filterNotNull()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
package expo.modules.video.records
|
|
2
|
+
|
|
3
|
+
import expo.modules.kotlin.records.Field
|
|
4
|
+
import expo.modules.kotlin.records.Record
|
|
5
|
+
|
|
6
|
+
data class ButtonOptions(
|
|
7
|
+
@Field val showNext: Boolean = false,
|
|
8
|
+
@Field val showPrevious: Boolean = false,
|
|
9
|
+
@Field val showSeekForward: Boolean = true,
|
|
10
|
+
@Field val showSeekBackward: Boolean = true,
|
|
11
|
+
@Field val showSubtitles: Boolean? = null,
|
|
12
|
+
@Field val showSettings: Boolean = true,
|
|
13
|
+
@Field val showPlayPause: Boolean = true,
|
|
14
|
+
@Field val showBottomBar: Boolean = true
|
|
15
|
+
) : Record
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
package expo.modules.video.records
|
|
2
|
+
|
|
3
|
+
import androidx.media3.common.util.UnstableApi
|
|
4
|
+
import expo.modules.kotlin.records.Field
|
|
5
|
+
import expo.modules.kotlin.records.Record
|
|
6
|
+
import java.io.Serializable
|
|
7
|
+
import kotlin.time.Duration
|
|
8
|
+
|
|
9
|
+
@UnstableApi
|
|
10
|
+
class PlayerBuilderOptions(
|
|
11
|
+
@Field var seekBackwardIncrement: Duration? = null,
|
|
12
|
+
@Field var seekForwardIncrement: Duration? = null
|
|
13
|
+
) : Record, Serializable
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
package expo.modules.video.records
|
|
2
2
|
|
|
3
|
+
import android.net.Uri
|
|
3
4
|
import androidx.annotation.OptIn
|
|
4
5
|
import androidx.media3.common.Format
|
|
5
6
|
import androidx.media3.common.util.UnstableApi
|
|
@@ -11,7 +12,10 @@ import java.util.Locale
|
|
|
11
12
|
class SubtitleTrack(
|
|
12
13
|
@Field val id: String,
|
|
13
14
|
@Field val language: String?,
|
|
14
|
-
@Field val label: String
|
|
15
|
+
@Field val label: String?,
|
|
16
|
+
@Field val name: String?,
|
|
17
|
+
@Field val isDefault: Boolean,
|
|
18
|
+
@Field val autoSelect: Boolean
|
|
15
19
|
) : Record, Serializable {
|
|
16
20
|
companion object {
|
|
17
21
|
fun fromFormat(format: Format?): SubtitleTrack? {
|
|
@@ -19,11 +23,17 @@ class SubtitleTrack(
|
|
|
19
23
|
val id = format.id ?: return null
|
|
20
24
|
val language = format.language ?: return null
|
|
21
25
|
val label = Locale(language).displayLanguage
|
|
26
|
+
val name = format.label
|
|
27
|
+
val isDefault = (format.selectionFlags and androidx.media3.common.C.SELECTION_FLAG_DEFAULT) != 0
|
|
28
|
+
val autoSelect = (format.selectionFlags and androidx.media3.common.C.SELECTION_FLAG_AUTOSELECT) != 0
|
|
22
29
|
|
|
23
30
|
return SubtitleTrack(
|
|
24
31
|
id = id,
|
|
25
32
|
language = language,
|
|
26
|
-
label = label
|
|
33
|
+
label = label,
|
|
34
|
+
name = name,
|
|
35
|
+
isDefault = isDefault,
|
|
36
|
+
autoSelect = autoSelect
|
|
27
37
|
)
|
|
28
38
|
}
|
|
29
39
|
}
|
|
@@ -32,7 +42,10 @@ class SubtitleTrack(
|
|
|
32
42
|
class AudioTrack(
|
|
33
43
|
@Field val id: String,
|
|
34
44
|
@Field val language: String?,
|
|
35
|
-
@Field val label: String
|
|
45
|
+
@Field val label: String?,
|
|
46
|
+
@Field val name: String?,
|
|
47
|
+
@Field val isDefault: Boolean,
|
|
48
|
+
@Field val autoSelect: Boolean
|
|
36
49
|
) : Record, Serializable {
|
|
37
50
|
companion object {
|
|
38
51
|
fun fromFormat(format: Format?): AudioTrack? {
|
|
@@ -40,11 +53,17 @@ class AudioTrack(
|
|
|
40
53
|
val id = format.id ?: return null
|
|
41
54
|
val language = format.language
|
|
42
55
|
val label = language?.let { Locale(it).displayLanguage } ?: "Unknown"
|
|
56
|
+
val name = format.label
|
|
57
|
+
val isDefault = (format.selectionFlags and androidx.media3.common.C.SELECTION_FLAG_DEFAULT) != 0
|
|
58
|
+
val autoSelect = (format.selectionFlags and androidx.media3.common.C.SELECTION_FLAG_AUTOSELECT) != 0
|
|
43
59
|
|
|
44
60
|
return AudioTrack(
|
|
45
61
|
id = id,
|
|
46
62
|
language = language,
|
|
47
|
-
label = label
|
|
63
|
+
label = label,
|
|
64
|
+
name = name,
|
|
65
|
+
isDefault = isDefault,
|
|
66
|
+
autoSelect = autoSelect
|
|
48
67
|
)
|
|
49
68
|
}
|
|
50
69
|
}
|
|
@@ -53,6 +72,7 @@ class AudioTrack(
|
|
|
53
72
|
@OptIn(UnstableApi::class)
|
|
54
73
|
class VideoTrack(
|
|
55
74
|
@Field val id: String,
|
|
75
|
+
@Field val url: Uri?,
|
|
56
76
|
@Field val size: VideoSize,
|
|
57
77
|
@Field val mimeType: String?,
|
|
58
78
|
@Field val isSupported: Boolean = true,
|
|
@@ -63,7 +83,7 @@ class VideoTrack(
|
|
|
63
83
|
var format: Format? = null
|
|
64
84
|
) : Record, Serializable {
|
|
65
85
|
companion object {
|
|
66
|
-
fun fromFormat(format: Format?, isSupported: Boolean): VideoTrack? {
|
|
86
|
+
fun fromFormat(format: Format?, isSupported: Boolean, variantUrl: Uri?): VideoTrack? {
|
|
67
87
|
val id = format?.id ?: return null
|
|
68
88
|
val size = VideoSize(format)
|
|
69
89
|
val mimeType = format.sampleMimeType
|
|
@@ -73,6 +93,7 @@ class VideoTrack(
|
|
|
73
93
|
|
|
74
94
|
return VideoTrack(
|
|
75
95
|
id = id,
|
|
96
|
+
url = variantUrl,
|
|
76
97
|
size = size,
|
|
77
98
|
mimeType = mimeType,
|
|
78
99
|
isSupported = isSupported,
|
package/build/VideoPlayer.d.ts
CHANGED
|
@@ -1,15 +1,17 @@
|
|
|
1
|
-
import { VideoSource, VideoPlayer } from './VideoPlayer.types';
|
|
1
|
+
import { VideoSource, VideoPlayer, PlayerBuilderOptions } from './VideoPlayer.types';
|
|
2
2
|
/**
|
|
3
3
|
* Creates a direct instance of `VideoPlayer` that doesn't release automatically.
|
|
4
4
|
*
|
|
5
5
|
* > **info** For most use cases you should use the [`useVideoPlayer`](#usevideoplayer) hook instead. See the [Using the VideoPlayer Directly](#using-the-videoplayer-directly) section for more details.
|
|
6
|
-
* @param source
|
|
6
|
+
* @param source - A video source that is used to initialize the player.
|
|
7
|
+
* @param playerBuilderOptions - Options to apply to the Android player builder before the native constructor is invoked.
|
|
7
8
|
*/
|
|
8
|
-
export declare function createVideoPlayer(source: VideoSource): VideoPlayer;
|
|
9
|
+
export declare function createVideoPlayer(source: VideoSource, playerBuilderOptions?: PlayerBuilderOptions): VideoPlayer;
|
|
9
10
|
/**
|
|
10
11
|
* Creates a `VideoPlayer`, which will be automatically cleaned up when the component is unmounted.
|
|
11
12
|
* @param source - A video source that is used to initialize the player.
|
|
12
13
|
* @param setup - A function that allows setting up the player. It will run after the player is created.
|
|
14
|
+
* @param playerBuilderOptions - Options to apply to the Android player builder before the native constructor is invoked.
|
|
13
15
|
*/
|
|
14
|
-
export declare function useVideoPlayer(source: VideoSource, setup?: (player: VideoPlayer) => void): VideoPlayer;
|
|
16
|
+
export declare function useVideoPlayer(source: VideoSource, setup?: (player: VideoPlayer) => void, playerBuilderOptions?: PlayerBuilderOptions): VideoPlayer;
|
|
15
17
|
//# sourceMappingURL=VideoPlayer.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"VideoPlayer.d.ts","sourceRoot":"","sources":["../src/VideoPlayer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAsBrF;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,MAAM,EAAE,WAAW,EACnB,oBAAoB,CAAC,EAAE,oBAAoB,GAC1C,WAAW,CAGb;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,MAAM,EAAE,WAAW,EACnB,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,WAAW,KAAK,IAAI,EACrC,oBAAoB,CAAC,EAAE,oBAAoB,GAC1C,WAAW,CAQb"}
|