expo-libvlc-player 3.2.3 → 3.2.5
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
CHANGED
|
@@ -43,34 +43,10 @@ For bare React Native projects, you must ensure that you have [installed and con
|
|
|
43
43
|
|
|
44
44
|
No additional configuration necessary.
|
|
45
45
|
|
|
46
|
-
#### Black screen issue
|
|
47
|
-
|
|
48
|
-
On Android, the `libvlcjni` player detaches from the View when surfaces are destroyed after switching screens.
|
|
49
|
-
|
|
50
|
-
The current workaround attaches the View once surfaces are created but this results in a brief black screen.
|
|
51
|
-
|
|
52
|
-
https://code.videolan.org/videolan/vlc-android/-/issues/1495
|
|
53
|
-
|
|
54
46
|
### Configure for iOS
|
|
55
47
|
|
|
56
48
|
Run `npx pod-install` after installing the npm package.
|
|
57
49
|
|
|
58
|
-
#### Local network privacy
|
|
59
|
-
|
|
60
|
-
On iOS, the `VLCKit` player seems to interact with the local network when playing media from external sources.
|
|
61
|
-
|
|
62
|
-
Starting in iOS 14, a clear message must be provided to the `NSLocalNetworkUsageDescription` key in the Info.plist file.
|
|
63
|
-
|
|
64
|
-
https://developer.apple.com/documentation/technotes/tn3179-understanding-local-network-privacy
|
|
65
|
-
|
|
66
|
-
#### Audio playback issue
|
|
67
|
-
|
|
68
|
-
On iOS, the `VLCKit` player experiences a small audio delay when resuming or muting media playback.
|
|
69
|
-
|
|
70
|
-
This might be related to the internal clock used by the library core causing inaccurate time values.
|
|
71
|
-
|
|
72
|
-
https://code.videolan.org/videolan/VLCKit/-/issues/233
|
|
73
|
-
|
|
74
50
|
### Configure for TV
|
|
75
51
|
|
|
76
52
|
Set the `EXPO_TV` environment variable, and run prebuild to make the TV modifications to the project.
|
|
@@ -268,6 +244,32 @@ The `LibVlcPlayerView` extends React Native `ViewProps` and implements the follo
|
|
|
268
244
|
}
|
|
269
245
|
```
|
|
270
246
|
|
|
247
|
+
## Known issues
|
|
248
|
+
|
|
249
|
+
#### Black screen
|
|
250
|
+
|
|
251
|
+
On Android, the `libvlcjni` player detaches from the View when its surface is destroyed after switching screens.
|
|
252
|
+
|
|
253
|
+
The current workaround attaches the View once a surface is created but this causes a brief black screen.
|
|
254
|
+
|
|
255
|
+
https://code.videolan.org/videolan/vlc-android/-/issues/1495
|
|
256
|
+
|
|
257
|
+
#### Local network
|
|
258
|
+
|
|
259
|
+
On iOS, the `VLCKit` player seems to interact with the local network when playing media from external sources.
|
|
260
|
+
|
|
261
|
+
A clear message must be provided to the `NSLocalNetworkUsageDescription` key in the Info.plist file.
|
|
262
|
+
|
|
263
|
+
https://developer.apple.com/documentation/technotes/tn3179-understanding-local-network-privacy
|
|
264
|
+
|
|
265
|
+
#### Audio delay
|
|
266
|
+
|
|
267
|
+
On iOS, the `VLCKit` player experiences a small audio delay when resuming or muting media playback.
|
|
268
|
+
|
|
269
|
+
This might be related to the internal clock used by the library core causing inaccurate time values.
|
|
270
|
+
|
|
271
|
+
https://code.videolan.org/videolan/VLCKit/-/issues/233
|
|
272
|
+
|
|
271
273
|
## Disclaimer
|
|
272
274
|
|
|
273
275
|
This project is not affiliated with, endorsed by, or officially supported by VideoLAN. The VLC icon is trademark of VideoLAN and is used here solely to indicate compatibility with the following **LibVLC** bindings:
|
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
apply plugin: "com.android.library"
|
|
2
2
|
|
|
3
3
|
group = "expo.modules.libvlcplayer"
|
|
4
|
-
version = "3.2.
|
|
4
|
+
version = "3.2.5"
|
|
5
5
|
|
|
6
6
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
7
7
|
apply from: expoModulesCorePlugin
|
|
@@ -27,7 +27,7 @@ android {
|
|
|
27
27
|
namespace "expo.modules.libvlcplayer"
|
|
28
28
|
defaultConfig {
|
|
29
29
|
versionCode 1
|
|
30
|
-
versionName "3.2.
|
|
30
|
+
versionName "3.2.5"
|
|
31
31
|
consumerProguardFiles("proguard-rules.pro")
|
|
32
32
|
}
|
|
33
33
|
lintOptions {
|
|
@@ -55,33 +55,33 @@ class LibVlcPlayerView(
|
|
|
55
55
|
addView(it)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
var libVLC: LibVLC? = null
|
|
59
|
+
var mediaPlayer: MediaPlayer? = null
|
|
60
60
|
private var media: Media? = null
|
|
61
|
-
|
|
61
|
+
var vlcDialog: VLCDialog? = null
|
|
62
62
|
|
|
63
|
-
|
|
64
|
-
|
|
63
|
+
var mediaLength: Long = 0L
|
|
64
|
+
var oldVolume: Int = MAX_PLAYER_VOLUME
|
|
65
65
|
|
|
66
66
|
private var shouldCreate: Boolean = false
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
67
|
+
var firstPlay: Boolean = false
|
|
68
|
+
var firstTime: Boolean = false
|
|
69
|
+
|
|
70
|
+
val onBuffering by EventDispatcher<Unit>()
|
|
71
|
+
val onPlaying by EventDispatcher<Unit>()
|
|
72
|
+
val onPaused by EventDispatcher<Unit>()
|
|
73
|
+
val onStopped by EventDispatcher<Unit>()
|
|
74
|
+
val onEndReached by EventDispatcher<Unit>()
|
|
75
|
+
val onEncounteredError by EventDispatcher()
|
|
76
|
+
val onDialogDisplay by EventDispatcher<Dialog>()
|
|
77
|
+
val onTimeChanged by EventDispatcher()
|
|
78
|
+
val onPositionChanged by EventDispatcher()
|
|
79
|
+
val onESAdded by EventDispatcher<MediaTracks>()
|
|
80
|
+
val onRecordChanged by EventDispatcher<Recording>()
|
|
81
|
+
val onSnapshotTaken by EventDispatcher()
|
|
82
|
+
val onFirstPlay by EventDispatcher<MediaInfo>()
|
|
83
|
+
val onForeground by EventDispatcher<Unit>()
|
|
84
|
+
val onBackground by EventDispatcher<Unit>()
|
|
85
85
|
|
|
86
86
|
init {
|
|
87
87
|
MediaPlayerManager.registerPlayerView(this)
|
|
@@ -99,6 +99,8 @@ class LibVlcPlayerView(
|
|
|
99
99
|
detachPlayer()
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
fun getTextureView(): TextureView? = playerView.findViewById(org.videolan.R.id.texture_video)
|
|
103
|
+
|
|
102
104
|
fun createPlayer() {
|
|
103
105
|
if (!shouldCreate) {
|
|
104
106
|
return
|
|
@@ -205,50 +207,53 @@ class LibVlcPlayerView(
|
|
|
205
207
|
|
|
206
208
|
fun setContentFit() {
|
|
207
209
|
mediaPlayer?.let { player ->
|
|
208
|
-
val textureView =
|
|
209
|
-
val video = player.getCurrentVideoTrack() ?: return
|
|
210
|
+
val textureView = getTextureView() ?: return
|
|
210
211
|
|
|
211
|
-
val
|
|
212
|
-
val viewHeight = playerView.height.toFloat()
|
|
212
|
+
val matrix = Matrix()
|
|
213
213
|
|
|
214
|
-
val
|
|
215
|
-
val videoHeight = video.height.toFloat()
|
|
214
|
+
val video = player.getCurrentVideoTrack()
|
|
216
215
|
|
|
217
|
-
|
|
218
|
-
|
|
216
|
+
if (video != null) {
|
|
217
|
+
val viewWidth = playerView.width.toFloat()
|
|
218
|
+
val viewHeight = playerView.height.toFloat()
|
|
219
219
|
|
|
220
|
-
|
|
221
|
-
|
|
220
|
+
val videoWidth = video.width.toFloat()
|
|
221
|
+
val videoHeight = video.height.toFloat()
|
|
222
222
|
|
|
223
|
-
|
|
223
|
+
val viewAspect = viewWidth / viewHeight
|
|
224
|
+
val videoAspect = videoWidth / videoHeight
|
|
224
225
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
226
|
+
val pivotX = viewWidth / 2f
|
|
227
|
+
val pivotY = viewHeight / 2f
|
|
228
|
+
|
|
229
|
+
when (contentFit) {
|
|
230
|
+
VideoContentFit.CONTAIN -> {
|
|
231
|
+
// No scale required
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
VideoContentFit.COVER -> {
|
|
235
|
+
val scale =
|
|
236
|
+
if (videoAspect > viewAspect) {
|
|
237
|
+
videoAspect / viewAspect
|
|
238
|
+
} else {
|
|
239
|
+
viewAspect / videoAspect
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
matrix.setScale(scale, scale, pivotX, pivotY)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
VideoContentFit.FILL -> {
|
|
246
|
+
var scaleX = 1f
|
|
247
|
+
var scaleY = 1f
|
|
229
248
|
|
|
230
|
-
VideoContentFit.COVER -> {
|
|
231
|
-
val scale =
|
|
232
249
|
if (videoAspect > viewAspect) {
|
|
233
|
-
videoAspect / viewAspect
|
|
250
|
+
scaleY = videoAspect / viewAspect
|
|
234
251
|
} else {
|
|
235
|
-
viewAspect / videoAspect
|
|
252
|
+
scaleX = viewAspect / videoAspect
|
|
236
253
|
}
|
|
237
254
|
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
VideoContentFit.FILL -> {
|
|
242
|
-
var scaleX = 1f
|
|
243
|
-
var scaleY = 1f
|
|
244
|
-
|
|
245
|
-
if (videoAspect > viewAspect) {
|
|
246
|
-
scaleY = videoAspect / viewAspect
|
|
247
|
-
} else {
|
|
248
|
-
scaleX = viewAspect / videoAspect
|
|
255
|
+
matrix.setScale(scaleX, scaleY, pivotX, pivotY)
|
|
249
256
|
}
|
|
250
|
-
|
|
251
|
-
matrix.setScale(scaleX, scaleY, pivotX, pivotY)
|
|
252
257
|
}
|
|
253
258
|
}
|
|
254
259
|
|
|
@@ -556,7 +561,7 @@ class LibVlcPlayerView(
|
|
|
556
561
|
fun snapshot(path: String) {
|
|
557
562
|
mediaPlayer?.let { player ->
|
|
558
563
|
try {
|
|
559
|
-
val textureView =
|
|
564
|
+
val textureView = getTextureView() ?: throw Exception()
|
|
560
565
|
val video = player.getCurrentVideoTrack() ?: throw Exception()
|
|
561
566
|
|
|
562
567
|
val surface = Surface(textureView.surfaceTexture)
|
|
@@ -620,7 +625,7 @@ class LibVlcPlayerView(
|
|
|
620
625
|
return this.any { option -> option in options }
|
|
621
626
|
}
|
|
622
627
|
|
|
623
|
-
|
|
628
|
+
fun ArrayList<String>.hasRepeatOption(): Boolean {
|
|
624
629
|
val options =
|
|
625
630
|
setOf(
|
|
626
631
|
"--input-repeat=",
|
|
@@ -635,7 +640,7 @@ class LibVlcPlayerView(
|
|
|
635
640
|
}
|
|
636
641
|
}
|
|
637
642
|
|
|
638
|
-
|
|
643
|
+
private fun ArrayList<String>.hasStartPausedOption(): Boolean {
|
|
639
644
|
val options =
|
|
640
645
|
setOf(
|
|
641
646
|
"--start-paused",
|
|
@@ -646,7 +651,7 @@ class LibVlcPlayerView(
|
|
|
646
651
|
return this.any { option -> option in options }
|
|
647
652
|
}
|
|
648
653
|
|
|
649
|
-
|
|
654
|
+
private fun ArrayList<String>.removeStartPausedOption() {
|
|
650
655
|
val options =
|
|
651
656
|
setOf(
|
|
652
657
|
"--start-paused",
|
|
@@ -7,7 +7,7 @@ import java.lang.ref.WeakReference
|
|
|
7
7
|
object MediaPlayerManager {
|
|
8
8
|
lateinit var audioFocusManager: AudioFocusManager
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
var playerViews: MutableList<WeakReference<LibVlcPlayerView>> = mutableListOf()
|
|
11
11
|
|
|
12
12
|
fun registerPlayerView(view: LibVlcPlayerView) {
|
|
13
13
|
playerViews.find { it.get() == view } ?: run { playerViews.add(WeakReference(view)) }
|
|
@@ -145,35 +145,37 @@ class LibVlcPlayerView: ExpoView {
|
|
|
145
145
|
|
|
146
146
|
func setContentFit() {
|
|
147
147
|
if let player = mediaPlayer {
|
|
148
|
+
var transform: CGAffineTransform = .identity
|
|
149
|
+
|
|
148
150
|
let view = playerView.bounds.size
|
|
149
151
|
let video = player.videoSize
|
|
150
152
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
153
|
+
if video != .zero {
|
|
154
|
+
let viewAspect = view.width / view.height
|
|
155
|
+
let videoAspect = video.width / video.height
|
|
156
|
+
|
|
157
|
+
switch contentFit {
|
|
158
|
+
case .contain:
|
|
159
|
+
// No transform required
|
|
160
|
+
break
|
|
161
|
+
case .cover:
|
|
162
|
+
let scale = videoAspect > viewAspect ?
|
|
163
|
+
videoAspect / viewAspect :
|
|
164
|
+
viewAspect / videoAspect
|
|
165
|
+
|
|
166
|
+
transform = CGAffineTransform(scaleX: scale, y: scale)
|
|
167
|
+
case .fill:
|
|
168
|
+
var scaleX = 1.0
|
|
169
|
+
var scaleY = 1.0
|
|
170
|
+
|
|
171
|
+
if videoAspect > viewAspect {
|
|
172
|
+
scaleY = videoAspect / viewAspect
|
|
173
|
+
} else {
|
|
174
|
+
scaleX = viewAspect / videoAspect
|
|
175
|
+
}
|
|
155
176
|
|
|
156
|
-
|
|
157
|
-
case .contain:
|
|
158
|
-
// No transform required
|
|
159
|
-
break
|
|
160
|
-
case .cover:
|
|
161
|
-
var scale = videoAspect > viewAspect ?
|
|
162
|
-
videoAspect / viewAspect :
|
|
163
|
-
viewAspect / videoAspect
|
|
164
|
-
|
|
165
|
-
transform = CGAffineTransform(scaleX: scale, y: scale)
|
|
166
|
-
case .fill:
|
|
167
|
-
var scaleX = 1.0
|
|
168
|
-
var scaleY = 1.0
|
|
169
|
-
|
|
170
|
-
if videoAspect > viewAspect {
|
|
171
|
-
scaleY = videoAspect / viewAspect
|
|
172
|
-
} else {
|
|
173
|
-
scaleX = viewAspect / videoAspect
|
|
177
|
+
transform = CGAffineTransform(scaleX: scaleX, y: scaleY)
|
|
174
178
|
}
|
|
175
|
-
|
|
176
|
-
transform = CGAffineTransform(scaleX: scaleX, y: scaleY)
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
playerView.transform = transform
|
|
@@ -188,9 +190,8 @@ class LibVlcPlayerView: ExpoView {
|
|
|
188
190
|
|
|
189
191
|
if let audios = player.audioTrackNames as? [String] {
|
|
190
192
|
if let audioIndexes = player.audioTrackIndexes as? [NSNumber] {
|
|
191
|
-
for (index, trackName) in audios
|
|
192
|
-
let
|
|
193
|
-
let track = Track(id: trackId, name: trackName)
|
|
193
|
+
for (index, trackName) in zip(audioIndexes, audios) {
|
|
194
|
+
let track = Track(id: index.intValue, name: trackName)
|
|
194
195
|
audioTracks.append(track)
|
|
195
196
|
}
|
|
196
197
|
}
|
|
@@ -200,9 +201,8 @@ class LibVlcPlayerView: ExpoView {
|
|
|
200
201
|
|
|
201
202
|
if let videos = player.videoTrackNames as? [String] {
|
|
202
203
|
if let videoIndexes = player.videoTrackIndexes as? [NSNumber] {
|
|
203
|
-
for (index, trackName) in videos
|
|
204
|
-
let
|
|
205
|
-
let track = Track(id: trackId, name: trackName)
|
|
204
|
+
for (index, trackName) in zip(videoIndexes, videos) {
|
|
205
|
+
let track = Track(id: index.intValue, name: trackName)
|
|
206
206
|
videoTracks.append(track)
|
|
207
207
|
}
|
|
208
208
|
}
|
|
@@ -212,9 +212,8 @@ class LibVlcPlayerView: ExpoView {
|
|
|
212
212
|
|
|
213
213
|
if let subtitles = player.videoSubTitlesNames as? [String] {
|
|
214
214
|
if let subtitleIndexes = player.videoSubTitlesIndexes as? [NSNumber] {
|
|
215
|
-
for (index, trackName) in subtitles
|
|
216
|
-
let
|
|
217
|
-
let track = Track(id: trackId, name: trackName)
|
|
215
|
+
for (index, trackName) in zip(subtitleIndexes, subtitles) {
|
|
216
|
+
let track = Track(id: index.intValue, name: trackName)
|
|
218
217
|
subtitleTracks.append(track)
|
|
219
218
|
}
|
|
220
219
|
}
|
|
@@ -536,7 +535,7 @@ extension Array where Element == String {
|
|
|
536
535
|
}
|
|
537
536
|
}
|
|
538
537
|
|
|
539
|
-
extension Array where Element == String {
|
|
538
|
+
private extension Array where Element == String {
|
|
540
539
|
func hasStartPausedOption() -> Bool {
|
|
541
540
|
let options = [
|
|
542
541
|
"--start-paused",
|
|
@@ -548,7 +547,7 @@ extension Array where Element == String {
|
|
|
548
547
|
}
|
|
549
548
|
}
|
|
550
549
|
|
|
551
|
-
extension Array where Element == String {
|
|
550
|
+
private extension Array where Element == String {
|
|
552
551
|
mutating func removeStartPausedOption() {
|
|
553
552
|
let options = [
|
|
554
553
|
"--start-paused",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "expo-libvlc-player",
|
|
3
|
-
"version": "3.2.
|
|
3
|
+
"version": "3.2.5",
|
|
4
4
|
"description": "LibVLC Player for Expo",
|
|
5
5
|
"main": "build/index.js",
|
|
6
6
|
"types": "build/index.d.ts",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"@eslint/js": "^9.30.0",
|
|
36
36
|
"@types/react": "~19.0.0",
|
|
37
37
|
"eslint": "^9.30.0",
|
|
38
|
-
"expo": "~53.0.
|
|
38
|
+
"expo": "~53.0.27",
|
|
39
39
|
"expo-module-scripts": "^4.1.6",
|
|
40
40
|
"globals": "^16.2.0",
|
|
41
41
|
"husky": "^9.1.7",
|