expo-libmpv 0.2.5 → 0.3.0
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/android/build.gradle +2 -2
- package/android/src/main/java/com/libmpv/LibmpvVideoModule.kt +91 -83
- package/android/src/main/java/com/libmpv/LibmpvVideoView.kt +42 -7
- package/android/src/main/java/com/libmpv/LibmpvWrapper.kt +56 -58
- package/app.json +1 -1
- package/build/LibmpvVideoView.d.ts.map +1 -1
- package/build/LibmpvVideoView.js +7 -0
- package/build/LibmpvVideoView.js.map +1 -1
- package/package.json +1 -1
- package/src/LibmpvVideoView.tsx +8 -0
package/android/build.gradle
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
apply plugin: 'com.android.library'
|
|
2
2
|
|
|
3
3
|
group = 'com.libmpv'
|
|
4
|
-
version = '0.
|
|
4
|
+
version = '0.3.0'
|
|
5
5
|
def expoModulesCorePlugin = new File(project(":expo-modules-core").projectDir.absolutePath, "ExpoModulesCorePlugin.gradle")
|
|
6
6
|
apply from: expoModulesCorePlugin
|
|
7
7
|
applyKotlinExpoModulesCorePlugin()
|
|
@@ -43,7 +43,7 @@ android {
|
|
|
43
43
|
namespace "com.libmpv"
|
|
44
44
|
defaultConfig {
|
|
45
45
|
versionCode 1
|
|
46
|
-
versionName "0.
|
|
46
|
+
versionName "0.3.0"
|
|
47
47
|
}
|
|
48
48
|
lintOptions {
|
|
49
49
|
abortOnError false
|
|
@@ -7,99 +7,107 @@ class LibmpvVideoModule : Module() {
|
|
|
7
7
|
override fun definition() = ModuleDefinition {
|
|
8
8
|
Name("LibmpvVideo")
|
|
9
9
|
View(LibmpvVideoView::class) {
|
|
10
|
-
|
|
10
|
+
Events("onLibmpvLog", "onLibmpvEvent")
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
12
|
+
AsyncFunction("runCommand") { view: LibmpvVideoView, orders: String ->
|
|
13
|
+
view.runCommand(orders)
|
|
14
|
+
}
|
|
15
15
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
AsyncFunction("setOptionString") { view: LibmpvVideoView, options: String ->
|
|
17
|
+
view.setOptionString(options)
|
|
18
|
+
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
view.mpv.play(playUrl)
|
|
24
|
-
} else {
|
|
25
|
-
view.attemptCreation()
|
|
26
|
-
}
|
|
27
|
-
view.log("setPlayUrl", playUrl)
|
|
28
|
-
}
|
|
20
|
+
AsyncFunction("cleanup") { view: LibmpvVideoView ->
|
|
21
|
+
view.cleanup()
|
|
22
|
+
}
|
|
29
23
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
24
|
+
Prop("playUrl") { view: LibmpvVideoView, playUrl: String ->
|
|
25
|
+
view.playUrl = playUrl
|
|
26
|
+
if (view.isSurfaceReady()) {
|
|
27
|
+
view.mpv.play(playUrl)
|
|
28
|
+
} else {
|
|
29
|
+
view.attemptCreation()
|
|
30
|
+
}
|
|
31
|
+
view.log("setPlayUrl", playUrl)
|
|
32
|
+
}
|
|
39
33
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
34
|
+
Prop("useHardwareDecoder") { view: LibmpvVideoView, useHardwareDecoder: Boolean ->
|
|
35
|
+
view.useHardwareDecoder = useHardwareDecoder
|
|
36
|
+
if (view.isSurfaceReady()) {
|
|
37
|
+
view.setHardwareDecoder(useHardwareDecoder)
|
|
38
|
+
} else {
|
|
39
|
+
view.attemptCreation()
|
|
40
|
+
}
|
|
41
|
+
view.log("setUseHardwareDecoder", "$useHardwareDecoder")
|
|
42
|
+
}
|
|
49
43
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
44
|
+
Prop("surfaceWidth") { view: LibmpvVideoView, surfaceWidth: Int ->
|
|
45
|
+
view.surfaceWidth = surfaceWidth
|
|
46
|
+
if (view.isSurfaceReady()) {
|
|
47
|
+
view.mpv.setSurfaceWidth(surfaceWidth)
|
|
48
|
+
} else {
|
|
49
|
+
view.attemptCreation()
|
|
50
|
+
}
|
|
51
|
+
view.log("setSurfaceWidth", "$surfaceWidth")
|
|
52
|
+
}
|
|
59
53
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
54
|
+
Prop("surfaceHeight") { view: LibmpvVideoView, surfaceHeight: Int ->
|
|
55
|
+
view.surfaceHeight = surfaceHeight
|
|
56
|
+
if (view.isSurfaceReady()) {
|
|
57
|
+
view.mpv.setSurfaceHeight(surfaceHeight)
|
|
58
|
+
} else {
|
|
59
|
+
view.attemptCreation()
|
|
60
|
+
}
|
|
61
|
+
view.log("setSurfaceHeight", "$surfaceHeight")
|
|
62
|
+
}
|
|
70
63
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
64
|
+
Prop("selectedAudioTrack") { view: LibmpvVideoView, audioTrackIndex: Int ->
|
|
65
|
+
view.audioIndex = audioTrackIndex
|
|
66
|
+
if (view.isSurfaceReady()) {
|
|
67
|
+
val mpvIndex = if (audioTrackIndex != -1) (audioTrackIndex + 1).toString() else "no"
|
|
68
|
+
view.mpv.setOptionString("aid", mpvIndex)
|
|
69
|
+
} else {
|
|
70
|
+
view.attemptCreation()
|
|
71
|
+
}
|
|
72
|
+
view.log("selectAudioTrack", "$audioTrackIndex")
|
|
73
|
+
}
|
|
81
74
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
75
|
+
Prop("selectedSubtitleTrack") { view: LibmpvVideoView, subtitleTrackIndex: Int ->
|
|
76
|
+
view.subtitleIndex = subtitleTrackIndex
|
|
77
|
+
if (view.isSurfaceReady()) {
|
|
78
|
+
val mpvIndex = if (subtitleTrackIndex != -1) (subtitleTrackIndex + 1).toString() else "no"
|
|
79
|
+
view.mpv.setOptionString("sid", mpvIndex)
|
|
80
|
+
} else {
|
|
81
|
+
view.attemptCreation()
|
|
82
|
+
}
|
|
83
|
+
view.log("selectSubtitleTrack", "$subtitleTrackIndex")
|
|
84
|
+
}
|
|
88
85
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
86
|
+
Prop("seekToSeconds") { view: LibmpvVideoView, seconds: Int ->
|
|
87
|
+
if (view.isSurfaceReady()) {
|
|
88
|
+
view.mpv.seekToSeconds(seconds)
|
|
89
|
+
}
|
|
90
|
+
view.log("seekToSeconds", "$seconds")
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
Prop("isPlaying") { view: LibmpvVideoView, isPlaying: Boolean ->
|
|
94
|
+
if (view.isSurfaceReady() && view.mpv.hasPlayedOnce()) {
|
|
95
|
+
when {
|
|
96
|
+
isPlaying && !view.mpv.isPlaying() -> {
|
|
97
|
+
view.mpv.unpause()
|
|
98
|
+
}
|
|
99
|
+
!isPlaying && view.mpv.isPlaying() -> {
|
|
100
|
+
view.mpv.pause()
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
view.attemptCreation()
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
OnViewDestroys { view: LibmpvVideoView ->
|
|
109
|
+
view.cleanup()
|
|
110
|
+
}
|
|
103
111
|
}
|
|
104
112
|
}
|
|
105
113
|
}
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
package com.libmpv
|
|
2
2
|
|
|
3
3
|
import android.content.Context
|
|
4
|
+
import android.os.Handler
|
|
5
|
+
import android.os.Looper
|
|
4
6
|
import android.view.SurfaceHolder
|
|
5
7
|
import android.view.SurfaceView
|
|
6
8
|
import android.widget.FrameLayout
|
|
9
|
+
import androidx.lifecycle.DefaultLifecycleObserver
|
|
10
|
+
import androidx.lifecycle.LifecycleOwner
|
|
7
11
|
import dev.jdtech.mpv.MPVLib
|
|
8
12
|
import expo.modules.kotlin.AppContext
|
|
9
13
|
import expo.modules.kotlin.views.ExpoView
|
|
@@ -41,12 +45,18 @@ class LibmpvVideoView(context: Context, appContext: AppContext) :
|
|
|
41
45
|
FrameLayout.LayoutParams.MATCH_PARENT,
|
|
42
46
|
FrameLayout.LayoutParams.MATCH_PARENT
|
|
43
47
|
)
|
|
44
|
-
|
|
48
|
+
appContext.activityProvider?.currentActivity?.let { activity ->
|
|
49
|
+
if (activity is androidx.lifecycle.LifecycleOwner) {
|
|
50
|
+
activity.lifecycle.addObserver(object : DefaultLifecycleObserver {
|
|
51
|
+
override fun onDestroy(owner: LifecycleOwner) {
|
|
52
|
+
log("LibmpvVideoView", "Lifecycle onDestroy -> cleanup()")
|
|
53
|
+
cleanup()
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
}
|
|
45
57
|
}
|
|
46
58
|
|
|
47
|
-
|
|
48
|
-
surfaceView.holder.removeCallback(this)
|
|
49
|
-
mpv.cleanup()
|
|
59
|
+
addView(surfaceView, layoutParams)
|
|
50
60
|
}
|
|
51
61
|
|
|
52
62
|
fun isSurfaceReady(): Boolean = isSurfaceCreated
|
|
@@ -176,10 +186,30 @@ class LibmpvVideoView(context: Context, appContext: AppContext) :
|
|
|
176
186
|
|
|
177
187
|
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {}
|
|
178
188
|
|
|
189
|
+
fun cleanup() {
|
|
190
|
+
// Launch on background executor so UI returns immediately
|
|
191
|
+
Thread {
|
|
192
|
+
try {
|
|
193
|
+
try { mpv.setPropertyString("pause", "yes") } catch (_: Throwable) {}
|
|
194
|
+
try { mpv.setPropertyString("ao", "null") } catch (_: Throwable) {}
|
|
195
|
+
Handler(Looper.getMainLooper()).post {
|
|
196
|
+
try {
|
|
197
|
+
surfaceView.holder.removeCallback(this@LibmpvVideoView)
|
|
198
|
+
mpv.cleanup()
|
|
199
|
+
} catch (e: Exception) {
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
} catch (_: Throwable) {}
|
|
203
|
+
}.start()
|
|
204
|
+
}
|
|
205
|
+
|
|
179
206
|
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
207
|
+
try {
|
|
208
|
+
mpv.setPropertyString("pause", "yes")
|
|
209
|
+
mpv.setPropertyString("vo", "null")
|
|
210
|
+
mpv.setPropertyString("force-window", "no")
|
|
211
|
+
} catch (_: Throwable) {}
|
|
212
|
+
try { mpv.detachSurface() } catch (_: Throwable) {}
|
|
183
213
|
}
|
|
184
214
|
|
|
185
215
|
// MPVLib.LogObserver
|
|
@@ -237,4 +267,9 @@ class LibmpvVideoView(context: Context, appContext: AppContext) :
|
|
|
237
267
|
"kind" to "eventId"
|
|
238
268
|
))
|
|
239
269
|
}
|
|
270
|
+
|
|
271
|
+
override fun onDetachedFromWindow() {
|
|
272
|
+
super.onDetachedFromWindow()
|
|
273
|
+
cleanup()
|
|
274
|
+
}
|
|
240
275
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
package com.libmpv
|
|
2
2
|
|
|
3
|
+
import android.os.Handler
|
|
4
|
+
import android.os.Looper
|
|
3
5
|
import android.content.Context
|
|
4
6
|
import android.util.Log
|
|
5
7
|
import android.view.SurfaceView
|
|
@@ -15,7 +17,10 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
15
17
|
private var swallow = true
|
|
16
18
|
}
|
|
17
19
|
|
|
18
|
-
private var created = false
|
|
20
|
+
@Volatile private var created = false
|
|
21
|
+
@Volatile private var destroying = false
|
|
22
|
+
@Volatile private var isDestroyed = false
|
|
23
|
+
@Volatile private var cleaning = false
|
|
19
24
|
private var isPlaying = false
|
|
20
25
|
private var hasPlayedOnce = false
|
|
21
26
|
private var eventObserver: MPVLib.EventObserver? = null
|
|
@@ -39,6 +44,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
39
44
|
fun getMpvDirectoryPath(): String? = mpvDirectory
|
|
40
45
|
|
|
41
46
|
private fun createMpvDirectory() {
|
|
47
|
+
if (isDestroyed) return
|
|
42
48
|
val mpvDir = File(applicationContext.getExternalFilesDir("mpv"), "mpv")
|
|
43
49
|
try {
|
|
44
50
|
mpvDirectory = mpvDir.absolutePath
|
|
@@ -68,6 +74,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
68
74
|
}
|
|
69
75
|
|
|
70
76
|
private fun logException(exception: Exception) {
|
|
77
|
+
if (isDestroyed) return
|
|
71
78
|
try {
|
|
72
79
|
val message: String = (exception.message as? String) ?: "Unable to read error message"
|
|
73
80
|
logObserver?.logMessage("RNLE", 20, message)
|
|
@@ -77,6 +84,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
77
84
|
}
|
|
78
85
|
|
|
79
86
|
fun addEventObserver(observer: MPVLib.EventObserver) {
|
|
87
|
+
if (isDestroyed) return
|
|
80
88
|
try {
|
|
81
89
|
if (!created) return
|
|
82
90
|
mpv.removeObservers()
|
|
@@ -97,6 +105,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
97
105
|
}
|
|
98
106
|
|
|
99
107
|
fun addLogObserver(observer: MPVLib.LogObserver) {
|
|
108
|
+
if (isDestroyed) return
|
|
100
109
|
try {
|
|
101
110
|
if (!created) return
|
|
102
111
|
mpv.removeLogObservers()
|
|
@@ -109,6 +118,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
109
118
|
}
|
|
110
119
|
|
|
111
120
|
fun setOptionString(option: String, setting: String) {
|
|
121
|
+
if (isDestroyed) return
|
|
112
122
|
try {
|
|
113
123
|
if (created) mpv.setOptionString(option, setting)
|
|
114
124
|
} catch (e: Exception) {
|
|
@@ -118,6 +128,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
118
128
|
}
|
|
119
129
|
|
|
120
130
|
fun setPropertyString(property: String, setting: String) {
|
|
131
|
+
if (isDestroyed) return
|
|
121
132
|
try {
|
|
122
133
|
if (created) mpv.setPropertyString(property, setting)
|
|
123
134
|
} catch (e: Exception) {
|
|
@@ -127,6 +138,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
127
138
|
}
|
|
128
139
|
|
|
129
140
|
fun init() {
|
|
141
|
+
if (isDestroyed) return
|
|
130
142
|
try {
|
|
131
143
|
if (created) mpv.init()
|
|
132
144
|
} catch (e: Exception) {
|
|
@@ -136,6 +148,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
136
148
|
}
|
|
137
149
|
|
|
138
150
|
fun command(orders: Array<String>) {
|
|
151
|
+
if (isDestroyed) return
|
|
139
152
|
try {
|
|
140
153
|
if (created) mpv.command(orders)
|
|
141
154
|
} catch (e: Exception) {
|
|
@@ -145,6 +158,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
145
158
|
}
|
|
146
159
|
|
|
147
160
|
fun attachSurface(surfaceView: SurfaceView) {
|
|
161
|
+
if (isDestroyed) return
|
|
148
162
|
try {
|
|
149
163
|
if (created) {
|
|
150
164
|
this.surfaceView = surfaceView
|
|
@@ -158,6 +172,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
158
172
|
}
|
|
159
173
|
|
|
160
174
|
fun play(url: String, options: String? = null) {
|
|
175
|
+
if (isDestroyed) return
|
|
161
176
|
if (!isPlaying) {
|
|
162
177
|
if (options == null) {
|
|
163
178
|
command(arrayOf("loadfile", url))
|
|
@@ -171,11 +186,13 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
171
186
|
}
|
|
172
187
|
|
|
173
188
|
fun pauseOrUnpause() {
|
|
189
|
+
if (isDestroyed) return
|
|
174
190
|
if (!hasPlayedOnce) return
|
|
175
191
|
if (isPlaying) pause() else unpause()
|
|
176
192
|
}
|
|
177
193
|
|
|
178
194
|
fun pause() {
|
|
195
|
+
if (isDestroyed) return
|
|
179
196
|
if (!hasPlayedOnce) return
|
|
180
197
|
if (isPlaying) {
|
|
181
198
|
command(arrayOf("set", "pause", "yes"))
|
|
@@ -184,6 +201,7 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
184
201
|
}
|
|
185
202
|
|
|
186
203
|
fun unpause() {
|
|
204
|
+
if (isDestroyed) return
|
|
187
205
|
if (!hasPlayedOnce) return
|
|
188
206
|
if (!isPlaying) {
|
|
189
207
|
command(arrayOf("set", "pause", "no"))
|
|
@@ -192,12 +210,14 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
192
210
|
}
|
|
193
211
|
|
|
194
212
|
fun seekToSeconds(seconds: Int) {
|
|
213
|
+
if (isDestroyed) return
|
|
195
214
|
if (created) {
|
|
196
215
|
command(arrayOf("seek", seconds.toString(), "absolute"))
|
|
197
216
|
}
|
|
198
217
|
}
|
|
199
218
|
|
|
200
219
|
private fun applySurfaceDimensions() {
|
|
220
|
+
if (isDestroyed) return
|
|
201
221
|
if (surfaceHeight != -1 && surfaceWidth != -1 && surfaceView != null) {
|
|
202
222
|
surfaceView?.holder?.setFixedSize(surfaceWidth, surfaceHeight)
|
|
203
223
|
}
|
|
@@ -213,64 +233,42 @@ class LibmpvWrapper(private val applicationContext: Context) {
|
|
|
213
233
|
applySurfaceDimensions()
|
|
214
234
|
}
|
|
215
235
|
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
} catch (e: Exception) {
|
|
220
|
-
logException(e)
|
|
221
|
-
if (!swallow) throw e
|
|
222
|
-
}
|
|
223
|
-
}
|
|
236
|
+
fun detachSurface(){
|
|
237
|
+
if(isDestroyed) return
|
|
238
|
+
try{
|
|
224
239
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
mpv.removeObservers()
|
|
228
|
-
} catch (e: Exception) {
|
|
229
|
-
logException(e)
|
|
230
|
-
if (!swallow) throw e
|
|
231
|
-
}
|
|
232
|
-
try {
|
|
233
|
-
mpv.removeLogObservers()
|
|
234
|
-
} catch (e: Exception) {
|
|
235
|
-
if (!swallow) throw e
|
|
236
|
-
}
|
|
237
|
-
try {
|
|
238
|
-
mpv.destroy()
|
|
239
|
-
created = false
|
|
240
|
-
} catch (e: Exception) {
|
|
241
|
-
logException(e)
|
|
242
|
-
if (!swallow) throw e
|
|
243
|
-
}
|
|
244
|
-
}
|
|
240
|
+
}catch(swallow:Exception){}
|
|
241
|
+
}
|
|
245
242
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
try {
|
|
269
|
-
destroy()
|
|
270
|
-
} catch (e: Exception) {
|
|
271
|
-
logException(e)
|
|
272
|
-
if (!swallow) throw e
|
|
273
|
-
}
|
|
274
|
-
}
|
|
243
|
+
|
|
244
|
+
fun cleanup() {
|
|
245
|
+
if (!created || cleaning) return
|
|
246
|
+
cleaning = true
|
|
247
|
+
|
|
248
|
+
Thread {
|
|
249
|
+
try {
|
|
250
|
+
safe { command(arrayOf("stop")) }
|
|
251
|
+
safe { setPropertyString("pause", "yes") }
|
|
252
|
+
safe { setPropertyString("vo", "null") }
|
|
253
|
+
safe { setPropertyString("ao", "null") }
|
|
254
|
+
safe { detachSurface() }
|
|
255
|
+
Handler(Looper.getMainLooper()).post {
|
|
256
|
+
safe { mpv.removeObservers() }
|
|
257
|
+
safe { mpv.removeLogObservers() }
|
|
258
|
+
safe { mpv.destroy() }
|
|
259
|
+
created = false
|
|
260
|
+
cleaning = false
|
|
261
|
+
}
|
|
262
|
+
} catch (e: Exception) {
|
|
263
|
+
logException(e)
|
|
264
|
+
cleaning = false
|
|
275
265
|
}
|
|
266
|
+
}.start()
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
private inline fun safe(block: () -> Unit) {
|
|
270
|
+
try { if (created) block() } catch (e: Exception) { logException(e) }
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
fun destroy() = cleanup()
|
|
276
274
|
}
|
package/app.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LibmpvVideoView.d.ts","sourceRoot":"","sources":["../src/LibmpvVideoView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAmChF,eAAO,MAAM,WAAW,+
|
|
1
|
+
{"version":3,"file":"LibmpvVideoView.d.ts","sourceRoot":"","sources":["../src/LibmpvVideoView.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAmChF,eAAO,MAAM,WAAW,+GAsDtB,CAAA;AAEF,eAAe,WAAW,CAAA"}
|
package/build/LibmpvVideoView.js
CHANGED
|
@@ -30,6 +30,13 @@ const EVENT_LOOKUP = {
|
|
|
30
30
|
};
|
|
31
31
|
const LibmpvVideoView = requireNativeView('LibmpvVideo');
|
|
32
32
|
export const LibmpvVideo = React.forwardRef((props, parentRef) => {
|
|
33
|
+
React.useEffect(() => {
|
|
34
|
+
return () => {
|
|
35
|
+
if (parentRef?.current?.cleanup) {
|
|
36
|
+
parentRef.current.cleanup();
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}, []);
|
|
33
40
|
// Pass mpv events and logs back up to the parent
|
|
34
41
|
const onLogEvent = (libmpvEvent) => {
|
|
35
42
|
if (props.onLibmpvEvent) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"LibmpvVideoView.js","sourceRoot":"","sources":["../src/LibmpvVideoView.tsx"],"names":[],"mappings":"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","sourcesContent":["import { requireNativeView } from 'expo';\nimport * as React from 'react';\n\nimport { LibmpvVideoViewProps, LibmpvNativeMethods } from './LibmpvVideo.types';\n\nconst styles: any = {\n videoPlayer: {\n position: \"absolute\",\n left: 0,\n bottom: 0,\n right: 0,\n top: 0\n }\n};\n\nconst EVENT_LOOKUP: any = {\n 0: 'NONE',\n 1: 'SHUTDOWN',\n 2: 'LOG_MESSAGE',\n 3: 'GET_PROPERTY_REPLY',\n 4: 'SET_PROPERTY_REPLY',\n 5: 'COMMAND_REPLY',\n 6: 'START_FILE',\n 7: 'END_FILE',\n 8: 'FILE_LOADED',\n 16: 'CLIENT_MESSAGE',\n 17: 'VIDEO_RECONFIG',\n 18: 'AUDIO_RECONFIG',\n 20: 'SEEK',\n 21: 'PLAYBACK_RESTART',\n 22: 'PROPERTY_CHANGE',\n 24: 'QUEUE_OVERFLOW',\n 25: 'HOOK'\n}\n\nconst LibmpvVideoView: React.ComponentType<LibmpvVideoViewProps> =\n requireNativeView('LibmpvVideo');\n\nexport const LibmpvVideo = React.forwardRef<LibmpvNativeMethods, LibmpvVideoViewProps>((props: any, parentRef: any) => {\n // Pass mpv events and logs back up to the parent\n const onLogEvent = (libmpvEvent: any) => {\n if (props.onLibmpvEvent) {\n if (libmpvEvent && libmpvEvent.nativeEvent) {\n libmpvEvent = libmpvEvent.nativeEvent\n }\n if (libmpvEvent.eventId) {\n libmpvEvent.value = parseInt(libmpvEvent.eventId, 10)\n libmpvEvent.eventKind = EVENT_LOOKUP[libmpvEvent.eventId]\n }\n else if (libmpvEvent.kind === 'long' || libmpvEvent.kind === 'double') {\n libmpvEvent.value = Number(libmpvEvent.value)\n }\n else if (libmpvEvent.kind === 'boolean') {\n libmpvEvent.value = libmpvEvent.value === 'true'\n }\n return props.onLibmpvEvent(libmpvEvent)\n }\n }\n const onLibmpvLog = (libmpvLog: any) => {\n if (props.onLibmpvLog) {\n if (libmpvLog && libmpvLog.nativeEvent) {\n libmpvLog = libmpvLog.nativeEvent\n }\n return props.onLibmpvLog(libmpvLog);\n }\n }\n\n // The order props are handled in the native code is non-deterministic\n // Each native prop setter checks to see if all required props are set\n // Only then will it try to create an instance of mpv\n return <LibmpvVideoView\n ref={parentRef}\n style={props.surfaceStyle ? props.surfaceStyle : styles.videoPlayer}\n playUrl={props.playUrl}\n isPlaying={props.isPlaying}\n useHardwareDecoder={props.useHardwareDecoder}\n surfaceWidth={props.surfaceWidth}\n surfaceHeight={props.surfaceHeight}\n selectedAudioTrack={props.selectedAudioTrack}\n selectedSubtitleTrack={props.selectedSubtitleTrack}\n seekToSeconds={props.seekToSeconds}\n onLibmpvEvent={onLogEvent}\n onLibmpvLog={onLibmpvLog}\n />\n})\n\nexport default LibmpvVideo\n"]}
|
|
1
|
+
{"version":3,"file":"LibmpvVideoView.js","sourceRoot":"","sources":["../src/LibmpvVideoView.tsx"],"names":[],"mappings":"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","sourcesContent":["import { requireNativeView } from 'expo';\nimport * as React from 'react';\n\nimport { LibmpvVideoViewProps, LibmpvNativeMethods } from './LibmpvVideo.types';\n\nconst styles: any = {\n videoPlayer: {\n position: \"absolute\",\n left: 0,\n bottom: 0,\n right: 0,\n top: 0\n }\n};\n\nconst EVENT_LOOKUP: any = {\n 0: 'NONE',\n 1: 'SHUTDOWN',\n 2: 'LOG_MESSAGE',\n 3: 'GET_PROPERTY_REPLY',\n 4: 'SET_PROPERTY_REPLY',\n 5: 'COMMAND_REPLY',\n 6: 'START_FILE',\n 7: 'END_FILE',\n 8: 'FILE_LOADED',\n 16: 'CLIENT_MESSAGE',\n 17: 'VIDEO_RECONFIG',\n 18: 'AUDIO_RECONFIG',\n 20: 'SEEK',\n 21: 'PLAYBACK_RESTART',\n 22: 'PROPERTY_CHANGE',\n 24: 'QUEUE_OVERFLOW',\n 25: 'HOOK'\n}\n\nconst LibmpvVideoView: React.ComponentType<LibmpvVideoViewProps> =\n requireNativeView('LibmpvVideo');\n\nexport const LibmpvVideo = React.forwardRef<LibmpvNativeMethods, LibmpvVideoViewProps>((props: any, parentRef: any) => {\n React.useEffect(() => {\n return () => {\n if (parentRef?.current?.cleanup) {\n parentRef.current.cleanup();\n }\n };\n }, []);\n\n // Pass mpv events and logs back up to the parent\n const onLogEvent = (libmpvEvent: any) => {\n if (props.onLibmpvEvent) {\n if (libmpvEvent && libmpvEvent.nativeEvent) {\n libmpvEvent = libmpvEvent.nativeEvent\n }\n if (libmpvEvent.eventId) {\n libmpvEvent.value = parseInt(libmpvEvent.eventId, 10)\n libmpvEvent.eventKind = EVENT_LOOKUP[libmpvEvent.eventId]\n }\n else if (libmpvEvent.kind === 'long' || libmpvEvent.kind === 'double') {\n libmpvEvent.value = Number(libmpvEvent.value)\n }\n else if (libmpvEvent.kind === 'boolean') {\n libmpvEvent.value = libmpvEvent.value === 'true'\n }\n return props.onLibmpvEvent(libmpvEvent)\n }\n }\n const onLibmpvLog = (libmpvLog: any) => {\n if (props.onLibmpvLog) {\n if (libmpvLog && libmpvLog.nativeEvent) {\n libmpvLog = libmpvLog.nativeEvent\n }\n return props.onLibmpvLog(libmpvLog);\n }\n }\n\n // The order props are handled in the native code is non-deterministic\n // Each native prop setter checks to see if all required props are set\n // Only then will it try to create an instance of mpv\n return <LibmpvVideoView\n ref={parentRef}\n style={props.surfaceStyle ? props.surfaceStyle : styles.videoPlayer}\n playUrl={props.playUrl}\n isPlaying={props.isPlaying}\n useHardwareDecoder={props.useHardwareDecoder}\n surfaceWidth={props.surfaceWidth}\n surfaceHeight={props.surfaceHeight}\n selectedAudioTrack={props.selectedAudioTrack}\n selectedSubtitleTrack={props.selectedSubtitleTrack}\n seekToSeconds={props.seekToSeconds}\n onLibmpvEvent={onLogEvent}\n onLibmpvLog={onLibmpvLog}\n />\n})\n\nexport default LibmpvVideo\n"]}
|
package/package.json
CHANGED
package/src/LibmpvVideoView.tsx
CHANGED
|
@@ -37,6 +37,14 @@ const LibmpvVideoView: React.ComponentType<LibmpvVideoViewProps> =
|
|
|
37
37
|
requireNativeView('LibmpvVideo');
|
|
38
38
|
|
|
39
39
|
export const LibmpvVideo = React.forwardRef<LibmpvNativeMethods, LibmpvVideoViewProps>((props: any, parentRef: any) => {
|
|
40
|
+
React.useEffect(() => {
|
|
41
|
+
return () => {
|
|
42
|
+
if (parentRef?.current?.cleanup) {
|
|
43
|
+
parentRef.current.cleanup();
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
}, []);
|
|
47
|
+
|
|
40
48
|
// Pass mpv events and logs back up to the parent
|
|
41
49
|
const onLogEvent = (libmpvEvent: any) => {
|
|
42
50
|
if (props.onLibmpvEvent) {
|