@pigeonmal/react-native-video 7.0.0-beta.12 → 7.0.0-beta.15
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 +3 -3
- package/android/build.gradle +1 -1
- package/android/src/main/java/com/twg/video/core/player/DataSourceFactoryUtils.kt +1 -1
- package/android/src/main/java/com/twg/video/core/player/MediaItemUtils.kt +1 -0
- package/android/src/main/java/com/twg/video/core/utils/TrackUtils.kt +6 -25
- package/android/src/main/java/com/twg/video/hybrids/videoplayer/HybridVideoPlayer.kt +31 -29
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ Date: 19/12/2025
|
|
|
4
4
|
(Only android)
|
|
5
5
|
Install :
|
|
6
6
|
|
|
7
|
-
1. npm install @pigeonmal/react-native-video@beta react-native-nitro-fetch
|
|
7
|
+
1. npm install @pigeonmal/react-native-video@beta @pigeonmal/react-native-nitro-fetch
|
|
8
8
|
2. Add this to android/app/settings.gradle
|
|
9
9
|
|
|
10
10
|
```
|
|
@@ -12,8 +12,6 @@ include ':media3-ffmpeg-decoder'
|
|
|
12
12
|
project(':media3-ffmpeg-decoder').projectDir = file('../node_modules/@pigeonmal/react-native-video/android/media3-ffmpeg-decoder')
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
3. create a patch for react-native-nitro-fetch like in the patches/react-native-nitro-fetch@x.patch
|
|
16
|
-
|
|
17
15
|
---
|
|
18
16
|
|
|
19
17
|
Features:
|
|
@@ -31,6 +29,8 @@ Features:
|
|
|
31
29
|
- player.resetForReuse() stop playback and clear tracks
|
|
32
30
|
- player.progressEventInterval change the progress event interval
|
|
33
31
|
- bugfix: external subtitles in hls/dash
|
|
32
|
+
- bugfix: add langs to external subs
|
|
33
|
+
- bugfix: onloadstart
|
|
34
34
|
- nullable video player source : new VideoPlayer(undefined);
|
|
35
35
|
- TextTrack type replaced to PlayerTrack
|
|
36
36
|
- removed onTrackChange event
|
package/android/build.gradle
CHANGED
|
@@ -234,7 +234,7 @@ dependencies {
|
|
|
234
234
|
implementation "androidx.media3:media3-session:$media3_version"
|
|
235
235
|
|
|
236
236
|
api project(':media3-ffmpeg-decoder')
|
|
237
|
-
implementation project(':
|
|
237
|
+
implementation project(':pigeonmal_react-native-nitro-fetch')
|
|
238
238
|
|
|
239
239
|
if (ExoplayerDependencies.useExoplayerDash) {
|
|
240
240
|
implementation "androidx.media3:media3-exoplayer-dash:$media3_version"
|
|
@@ -60,7 +60,7 @@ fun buildHttpDataSourceFactory(context: Context, source: HybridVideoPlayerSource
|
|
|
60
60
|
fun buildCronetHttpDataSourceFactory(source: HybridVideoPlayerSourceSpec): CronetDataSource.Factory {
|
|
61
61
|
// Get Cronet engine and executor from NitroFetch
|
|
62
62
|
// used before NitroFetch.ioExecutor , but cause blocking thread
|
|
63
|
-
val factory = CronetDataSource.Factory(NitroFetch.getEngine(),
|
|
63
|
+
val factory = CronetDataSource.Factory(NitroFetch.getEngine(), NitroFetch.ioExecutor)
|
|
64
64
|
.setConnectionTimeoutMs(10_000)
|
|
65
65
|
.setReadTimeoutMs(10_000)
|
|
66
66
|
.setResetTimeoutOnRedirects(true)
|
|
@@ -92,6 +92,7 @@ fun getSubtitlesConfiguration(
|
|
|
92
92
|
.setSelectionFlags(0) // C.SELECTION_FLAG_DEFAULT
|
|
93
93
|
.setRoleFlags(C.ROLE_FLAG_SUBTITLE)
|
|
94
94
|
.setLabel(subtitle.label)
|
|
95
|
+
.setLanguage(subtitle.language)
|
|
95
96
|
.build()
|
|
96
97
|
subtitlesConfiguration.add(subtitleConfig)
|
|
97
98
|
} catch (e: Exception) {
|
|
@@ -27,13 +27,9 @@ object TrackUtils {
|
|
|
27
27
|
val language = format.language
|
|
28
28
|
val isSelected = trackGroup.isTrackSelected(trackIndex)
|
|
29
29
|
|
|
30
|
-
val isExternal = trackId.startsWith("external-") == true
|
|
31
|
-
|
|
32
|
-
val finalTrackId = if (isExternal) "external-$globalTrackIndex" else trackId
|
|
33
|
-
|
|
34
30
|
tracks.add(
|
|
35
31
|
PlayerTrack(
|
|
36
|
-
id =
|
|
32
|
+
id = trackId,
|
|
37
33
|
label = label,
|
|
38
34
|
language = language,
|
|
39
35
|
selected = isSelected
|
|
@@ -74,12 +70,7 @@ object TrackUtils {
|
|
|
74
70
|
val currentTrackId = format.id ?: "track-$type-$globalTrackIndex"
|
|
75
71
|
//val label = format.label ?: "Unknown ${globalTrackIndex + 1}"
|
|
76
72
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
val finalTrackId =
|
|
80
|
-
if (isExternal) "external-$globalTrackIndex" else currentTrackId
|
|
81
|
-
|
|
82
|
-
if (finalTrackId == id) {
|
|
73
|
+
if (currentTrackId == id) {
|
|
83
74
|
// Enable this specific track
|
|
84
75
|
trackSelector.setTrackTypeDisabled(type, false)
|
|
85
76
|
trackSelector.setOverrideForType(
|
|
@@ -169,12 +160,8 @@ object TrackUtils {
|
|
|
169
160
|
val label = format.label ?: "Unknown ${globalTrackIndex + 1}"
|
|
170
161
|
val language = format.language
|
|
171
162
|
|
|
172
|
-
val isExternal = trackId.startsWith("external-") == true
|
|
173
|
-
|
|
174
|
-
val finalTrackId = if (isExternal) "external-$globalTrackIndex" else trackId
|
|
175
|
-
|
|
176
163
|
return@runOnMainThreadSync PlayerTrack(
|
|
177
|
-
id =
|
|
164
|
+
id = trackId,
|
|
178
165
|
label = label,
|
|
179
166
|
language = language,
|
|
180
167
|
selected = true
|
|
@@ -210,8 +197,6 @@ object TrackUtils {
|
|
|
210
197
|
val format = trackGroup.getTrackFormat(trackIndex)
|
|
211
198
|
|
|
212
199
|
val rawId = format.id ?: "track-${C.TRACK_TYPE_AUDIO}-$globalAudioIndex"
|
|
213
|
-
val isExternal = rawId.startsWith("external-")
|
|
214
|
-
val finalId = if (isExternal) "external-$globalAudioIndex" else rawId
|
|
215
200
|
|
|
216
201
|
val label = format.label ?: "Unknown ${globalAudioIndex + 1}"
|
|
217
202
|
val language = format.language
|
|
@@ -219,7 +204,7 @@ object TrackUtils {
|
|
|
219
204
|
|
|
220
205
|
audioTracks.add(
|
|
221
206
|
PlayerTrack(
|
|
222
|
-
id =
|
|
207
|
+
id = rawId,
|
|
223
208
|
label = label,
|
|
224
209
|
language = language,
|
|
225
210
|
selected = isSelected
|
|
@@ -234,8 +219,6 @@ object TrackUtils {
|
|
|
234
219
|
val format = trackGroup.getTrackFormat(trackIndex)
|
|
235
220
|
|
|
236
221
|
val rawId = format.id ?: "track-${C.TRACK_TYPE_TEXT}-$globalTextIndex"
|
|
237
|
-
val isExternal = rawId.startsWith("external-")
|
|
238
|
-
val finalId = if (isExternal) "external-$globalTextIndex" else rawId
|
|
239
222
|
|
|
240
223
|
val label = format.label ?: "Unknown ${globalTextIndex + 1}"
|
|
241
224
|
val language = format.language
|
|
@@ -243,7 +226,7 @@ object TrackUtils {
|
|
|
243
226
|
|
|
244
227
|
textTracks.add(
|
|
245
228
|
PlayerTrack(
|
|
246
|
-
id =
|
|
229
|
+
id = rawId,
|
|
247
230
|
label = label,
|
|
248
231
|
language = language,
|
|
249
232
|
selected = isSelected
|
|
@@ -259,8 +242,6 @@ object TrackUtils {
|
|
|
259
242
|
val format = trackGroup.getTrackFormat(trackIndex)
|
|
260
243
|
|
|
261
244
|
val rawId = format.id ?: "track-${C.TRACK_TYPE_VIDEO}-$globalVideoIndex"
|
|
262
|
-
val isExternal = rawId.startsWith("external-")
|
|
263
|
-
val finalId = if (isExternal) "external-$globalVideoIndex" else rawId
|
|
264
245
|
|
|
265
246
|
val label = format.label ?: "Unknown ${globalVideoIndex + 1}"
|
|
266
247
|
val language = format.language
|
|
@@ -273,7 +254,7 @@ object TrackUtils {
|
|
|
273
254
|
VideoPlayerTrack(
|
|
274
255
|
width = width,
|
|
275
256
|
height = height,
|
|
276
|
-
id =
|
|
257
|
+
id = rawId,
|
|
277
258
|
label = label,
|
|
278
259
|
language = language,
|
|
279
260
|
selected = isSelected
|
|
@@ -261,18 +261,27 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
|
|
|
261
261
|
.setRenderersFactory(renderersFactory!!)
|
|
262
262
|
.build()
|
|
263
263
|
|
|
264
|
+
currentPlayerView?.get()?.player = player
|
|
265
|
+
|
|
264
266
|
loadedWithSource = true
|
|
265
267
|
|
|
266
268
|
player.addListener(playerListener)
|
|
267
269
|
player.addAnalyticsListener(analyticsListener)
|
|
268
270
|
|
|
269
|
-
|
|
271
|
+
setPlayerMediaSource(hybridSource)
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
fun setPlayerMediaSource(hybridSource: HybridVideoPlayerSource) {
|
|
275
|
+
val startPosition = hybridSource.config.startPosition
|
|
270
276
|
if (startPosition != null && startPosition > 0L) {
|
|
271
277
|
player.setMediaSource(hybridSource.mediaSource, startPosition)
|
|
272
278
|
} else {
|
|
273
279
|
player.setMediaSource(hybridSource.mediaSource)
|
|
274
280
|
}
|
|
281
|
+
}
|
|
275
282
|
|
|
283
|
+
fun preparePlayer(hybridSource: HybridVideoPlayerSource) {
|
|
284
|
+
player.prepare()
|
|
276
285
|
// Emit onLoadStart
|
|
277
286
|
val sourceType = if (hybridSource.uri.startsWith("http")) SourceType.NETWORK else SourceType.LOCAL
|
|
278
287
|
eventEmitter.onLoadStart(onLoadStartData(sourceType = sourceType, source = hybridSource))
|
|
@@ -282,9 +291,10 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
|
|
|
282
291
|
|
|
283
292
|
override fun initialize(): Promise<Unit> {
|
|
284
293
|
return Promise.async {
|
|
294
|
+
val hybridSource = source as? HybridVideoPlayerSource ?: throw PlayerError.InvalidSource
|
|
285
295
|
return@async runOnMainThreadSync {
|
|
286
296
|
initializePlayer()
|
|
287
|
-
|
|
297
|
+
preparePlayer(hybridSource)
|
|
288
298
|
}
|
|
289
299
|
}
|
|
290
300
|
}
|
|
@@ -295,7 +305,7 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
|
|
|
295
305
|
runOnMainThread {
|
|
296
306
|
if (source.config.initializeOnCreation == true) {
|
|
297
307
|
initializePlayer()
|
|
298
|
-
|
|
308
|
+
preparePlayer(source)
|
|
299
309
|
}
|
|
300
310
|
}
|
|
301
311
|
}
|
|
@@ -343,22 +353,19 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
|
|
|
343
353
|
initializePlayer()
|
|
344
354
|
} else {
|
|
345
355
|
renderersFactory?.setTextOffset((hybridSource.config.initialSubtitleDelay ?: 0L) * 1_000L)
|
|
346
|
-
|
|
347
|
-
if (startPosition != null && startPosition > 0L) {
|
|
348
|
-
player.setMediaSource(hybridSource.mediaSource, startPosition)
|
|
349
|
-
} else {
|
|
350
|
-
player.setMediaSource(hybridSource.mediaSource)
|
|
351
|
-
}
|
|
356
|
+
setPlayerMediaSource(hybridSource)
|
|
352
357
|
}
|
|
353
358
|
|
|
354
359
|
// Prepare player
|
|
355
|
-
|
|
360
|
+
preparePlayer(hybridSource)
|
|
356
361
|
}
|
|
357
362
|
}
|
|
358
363
|
}
|
|
359
364
|
|
|
360
365
|
override fun preload(): Promise<Unit> {
|
|
361
366
|
return Promise.async {
|
|
367
|
+
val hybridSource = source as? HybridVideoPlayerSource ?: throw PlayerError.InvalidSource
|
|
368
|
+
|
|
362
369
|
runOnMainThreadSync {
|
|
363
370
|
if (!loadedWithSource) {
|
|
364
371
|
initializePlayer()
|
|
@@ -368,7 +375,7 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
|
|
|
368
375
|
return@runOnMainThreadSync
|
|
369
376
|
}
|
|
370
377
|
|
|
371
|
-
|
|
378
|
+
preparePlayer(hybridSource)
|
|
372
379
|
}
|
|
373
380
|
}
|
|
374
381
|
}
|
|
@@ -492,21 +499,12 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
|
|
|
492
499
|
eventEmitter.onBuffer(false)
|
|
493
500
|
|
|
494
501
|
val allTracks = TrackUtils.getAllPlayerTracksInternal(player)
|
|
495
|
-
val
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
// We don't care for the true information, we use only width and height
|
|
502
|
-
id = "general",
|
|
503
|
-
label = "General",
|
|
504
|
-
selected = true,
|
|
505
|
-
language = null
|
|
506
|
-
)
|
|
507
|
-
}
|
|
508
|
-
val width = selectedVideo?.width ?: 0.0
|
|
509
|
-
val height = selectedVideo?.height ?: 0.0
|
|
502
|
+
val (width, height) = player.videoFormat?.let { format ->
|
|
503
|
+
format.width.toDouble() to format.height.toDouble()
|
|
504
|
+
} ?: allTracks.videos.firstOrNull { it.selected }?.let {
|
|
505
|
+
it.width to it.height
|
|
506
|
+
} ?: (0.0 to 0.0)
|
|
507
|
+
|
|
510
508
|
// val rotationDegrees = selectedVideoTrackFormat?.rotationDegrees ?: generalVideoFormat?.rotationDegrees
|
|
511
509
|
|
|
512
510
|
eventEmitter.onLoad(
|
|
@@ -653,10 +651,14 @@ class HybridVideoPlayer() : HybridVideoPlayerSpec(), AutoCloseable {
|
|
|
653
651
|
|
|
654
652
|
override fun resetForReuse() {
|
|
655
653
|
runOnMainThread {
|
|
656
|
-
if (
|
|
657
|
-
|
|
654
|
+
if (this.source != null) {
|
|
655
|
+
stopProgressUpdates()
|
|
656
|
+
this.source = null
|
|
657
|
+
if (player.playbackState != Player.STATE_IDLE) {
|
|
658
|
+
player.stop()
|
|
659
|
+
}
|
|
660
|
+
player.clearMediaItems()
|
|
658
661
|
}
|
|
659
|
-
player.clearMediaItems()
|
|
660
662
|
}
|
|
661
663
|
}
|
|
662
664
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pigeonmal/react-native-video",
|
|
3
|
-
"version": "7.0.0-beta.
|
|
3
|
+
"version": "7.0.0-beta.15",
|
|
4
4
|
"description": "<Video /> Component for React Native",
|
|
5
5
|
"source": "./src/index.tsx",
|
|
6
6
|
"main": "./lib/commonjs/index.js",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
"react": "*",
|
|
95
95
|
"react-native": "*",
|
|
96
96
|
"react-native-nitro-modules": ">=0.27.2",
|
|
97
|
-
"react-native-nitro-fetch": ">=0.1.
|
|
97
|
+
"@pigeonmal/react-native-nitro-fetch": ">=0.1.7"
|
|
98
98
|
},
|
|
99
99
|
"release-it": {
|
|
100
100
|
"npm": {
|