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.
@@ -1,7 +1,7 @@
1
1
  apply plugin: 'com.android.library'
2
2
 
3
3
  group = 'com.libmpv'
4
- version = '0.2.5'
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.2.5"
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
- Events("onLibmpvLog", "onLibmpvEvent")
10
+ Events("onLibmpvLog", "onLibmpvEvent")
11
11
 
12
- AsyncFunction("runCommand") { view: LibmpvVideoView, orders: String ->
13
- view.runCommand(orders)
14
- }
12
+ AsyncFunction("runCommand") { view: LibmpvVideoView, orders: String ->
13
+ view.runCommand(orders)
14
+ }
15
15
 
16
- AsyncFunction("setOptionString") { view: LibmpvVideoView, options: String ->
17
- view.setOptionString(options)
18
- }
16
+ AsyncFunction("setOptionString") { view: LibmpvVideoView, options: String ->
17
+ view.setOptionString(options)
18
+ }
19
19
 
20
- Prop("playUrl") { view: LibmpvVideoView, playUrl: String ->
21
- view.playUrl = playUrl
22
- if (view.isSurfaceReady()) {
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
- Prop("useHardwareDecoder") { view: LibmpvVideoView, useHardwareDecoder: Boolean ->
31
- view.useHardwareDecoder = useHardwareDecoder
32
- if (view.isSurfaceReady()) {
33
- view.setHardwareDecoder(useHardwareDecoder)
34
- } else {
35
- view.attemptCreation()
36
- }
37
- view.log("setUseHardwareDecoder", "$useHardwareDecoder")
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
- Prop("surfaceWidth") { view: LibmpvVideoView, surfaceWidth: Int ->
41
- view.surfaceWidth = surfaceWidth
42
- if (view.isSurfaceReady()) {
43
- view.mpv.setSurfaceWidth(surfaceWidth)
44
- } else {
45
- view.attemptCreation()
46
- }
47
- view.log("setSurfaceWidth", "$surfaceWidth")
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
- Prop("surfaceHeight") { view: LibmpvVideoView, surfaceHeight: Int ->
51
- view.surfaceHeight = surfaceHeight
52
- if (view.isSurfaceReady()) {
53
- view.mpv.setSurfaceHeight(surfaceHeight)
54
- } else {
55
- view.attemptCreation()
56
- }
57
- view.log("setSurfaceHeight", "$surfaceHeight")
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
- Prop("selectedAudioTrack") { view: LibmpvVideoView, audioTrackIndex: Int ->
61
- view.audioIndex = audioTrackIndex
62
- if (view.isSurfaceReady()) {
63
- val mpvIndex = if (audioTrackIndex != -1) (audioTrackIndex + 1).toString() else "no"
64
- view.mpv.setOptionString("aid", mpvIndex)
65
- } else {
66
- view.attemptCreation()
67
- }
68
- view.log("selectAudioTrack", "$audioTrackIndex")
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
- Prop("selectedSubtitleTrack") { view: LibmpvVideoView, subtitleTrackIndex: Int ->
72
- view.subtitleIndex = subtitleTrackIndex
73
- if (view.isSurfaceReady()) {
74
- val mpvIndex = if (subtitleTrackIndex != -1) (subtitleTrackIndex + 1).toString() else "no"
75
- view.mpv.setOptionString("sid", mpvIndex)
76
- } else {
77
- view.attemptCreation()
78
- }
79
- view.log("selectSubtitleTrack", "$subtitleTrackIndex")
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
- Prop("seekToSeconds") { view: LibmpvVideoView, seconds: Int ->
83
- if (view.isSurfaceReady()) {
84
- view.mpv.seekToSeconds(seconds)
85
- }
86
- view.log("seekToSeconds", "$seconds")
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
- Prop("isPlaying") { view: LibmpvVideoView, isPlaying: Boolean ->
90
- if (view.isSurfaceReady() && view.mpv.hasPlayedOnce()) {
91
- when {
92
- isPlaying && !view.mpv.isPlaying() -> {
93
- view.mpv.unpause()
94
- }
95
- !isPlaying && view.mpv.isPlaying() -> {
96
- view.mpv.pause()
97
- }
98
- }
99
- } else {
100
- view.attemptCreation()
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
- addView(surfaceView, layoutParams)
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
- fun cleanup() {
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
- mpv.setPropertyString("vo", "null")
181
- mpv.setPropertyString("force-window", "no")
182
- mpv.detachSurface()
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
- fun detachSurface() {
217
- try {
218
- mpv.detachSurface()
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
- fun destroy() {
226
- try {
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
- fun cleanup() {
247
- if (created) {
248
- try {
249
- pause()
250
- setPropertyString("vo", "null")
251
- setPropertyString("ao", "null")
252
- } catch (e: Exception) {
253
- logException(e)
254
- if (!swallow) throw e
255
- }
256
- try {
257
- setOptionString("force-window", "no")
258
- } catch (e: Exception) {
259
- logException(e)
260
- if (!swallow) throw e
261
- }
262
- try {
263
- detachSurface()
264
- } catch (e: Exception) {
265
- logException(e)
266
- if (!swallow) throw e
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,6 +1,6 @@
1
1
  {
2
2
  "expo": {
3
- "runtimeVersion": "0.2.5",
3
+ "runtimeVersion": "0.3.0",
4
4
  "plugins": [
5
5
  [
6
6
  "expo-build-properties",
@@ -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,+GA8CtB,CAAA;AAEF,eAAe,WAAW,CAAA"}
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"}
@@ -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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "expo-libmpv",
3
- "version": "0.2.5",
3
+ "version": "0.3.0",
4
4
  "description": "A libmpv Fabric component for Android",
5
5
  "main": "build/index.js",
6
6
  "types": "build/index.d.ts",
@@ -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) {