expo-libmpv 0.4.5 → 0.5.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 +3 -3
- package/android/src/main/java/com/libmpv/LibmpvRenderer.kt +400 -0
- package/android/src/main/java/com/libmpv/LibmpvSession.kt +52 -0
- package/android/src/main/java/com/libmpv/LibmpvView.kt +86 -255
- package/android/src/main/java/com/libmpv/LibmpvViewModule.kt +61 -91
- package/app.json +1 -1
- package/build/LibmpvView.d.ts.map +1 -1
- package/build/LibmpvView.js +5 -1
- package/build/LibmpvView.js.map +1 -1
- package/build/LibmpvViewTypes.d.ts +1 -0
- package/build/LibmpvViewTypes.d.ts.map +1 -1
- package/build/LibmpvViewTypes.js.map +1 -1
- package/package.json +1 -1
- package/src/LibmpvView.tsx +8 -1
- package/src/LibmpvViewTypes.ts +1 -0
- package/android/src/main/java/com/libmpv/LibmpvWrapper.kt +0 -297
package/src/LibmpvView.tsx
CHANGED
|
@@ -75,22 +75,29 @@ export const LibmpvView = React.forwardRef<LibmpvViewNativeMethods, LibmpvViewPr
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
+
let seekProps: any = {}
|
|
79
|
+
if (typeof props?.seekToSeconds === 'number' && props?.seekToSeconds > 0) {
|
|
80
|
+
seekProps.seekToSeconds = props.seekToSeconds
|
|
81
|
+
}
|
|
82
|
+
|
|
78
83
|
// The order props are handled in the native code is non-deterministic
|
|
79
84
|
// Each native prop setter checks to see if all required props are set
|
|
80
85
|
// Only then will it try to create an instance of mpv
|
|
86
|
+
|
|
81
87
|
return <LibmpvViewNative
|
|
82
88
|
ref={parentRef}
|
|
89
|
+
{...seekProps}
|
|
83
90
|
style={props.surfaceStyle ? props.surfaceStyle : styles.videoPlayer}
|
|
84
91
|
videoOutput={props.videoOutput}
|
|
85
92
|
playUrl={props.playUrl}
|
|
86
93
|
isPlaying={props.isPlaying}
|
|
87
94
|
decodingMode={props.decodingMode}
|
|
88
95
|
acceleratedCodecs={props.acceleratedCodecs}
|
|
96
|
+
videoSync={props.videoSync}
|
|
89
97
|
surfaceWidth={props.surfaceWidth}
|
|
90
98
|
surfaceHeight={props.surfaceHeight}
|
|
91
99
|
selectedAudioTrack={props.selectedAudioTrack}
|
|
92
100
|
selectedSubtitleTrack={props.selectedSubtitleTrack}
|
|
93
|
-
seekToSeconds={props.seekToSeconds}
|
|
94
101
|
onLibmpvEvent={onLogEvent}
|
|
95
102
|
onLibmpvLog={onLibmpvLog}
|
|
96
103
|
/>
|
package/src/LibmpvViewTypes.ts
CHANGED
|
@@ -1,297 +0,0 @@
|
|
|
1
|
-
package com.libmpv
|
|
2
|
-
|
|
3
|
-
import android.os.Handler
|
|
4
|
-
import android.os.Looper
|
|
5
|
-
import android.content.Context
|
|
6
|
-
import android.util.Log
|
|
7
|
-
import android.view.SurfaceView
|
|
8
|
-
import dev.jdtech.mpv.MPVLib
|
|
9
|
-
import java.io.File
|
|
10
|
-
import java.io.FileOutputStream
|
|
11
|
-
import java.io.InputStream
|
|
12
|
-
import java.io.OutputStream
|
|
13
|
-
|
|
14
|
-
class LibmpvWrapper(private val applicationContext: Context) {
|
|
15
|
-
companion object {
|
|
16
|
-
private const val TAG = "expo-libmpv"
|
|
17
|
-
private var SWALLOW = true
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
@Volatile private var created = false
|
|
21
|
-
@Volatile private var inited = false
|
|
22
|
-
@Volatile private var destroyed = false
|
|
23
|
-
@Volatile private var cleaning = false
|
|
24
|
-
@Volatile private var isPlaying = false
|
|
25
|
-
@Volatile private var hasPlayedOnce = false
|
|
26
|
-
|
|
27
|
-
private var mpvDirectory: String? = null
|
|
28
|
-
private var surfaceWidth: Int = -1
|
|
29
|
-
private var surfaceHeight: Int = -1
|
|
30
|
-
private var surfaceView: SurfaceView? = null
|
|
31
|
-
|
|
32
|
-
fun isCreated(): Boolean = created
|
|
33
|
-
fun isPlaying(): Boolean = isPlaying
|
|
34
|
-
fun hasPlayedOnce(): Boolean = hasPlayedOnce
|
|
35
|
-
fun getMpvDirectoryPath(): String? = mpvDirectory
|
|
36
|
-
|
|
37
|
-
private fun logException(exception: Exception) {
|
|
38
|
-
if (destroyed){ return }
|
|
39
|
-
try {
|
|
40
|
-
val message: String = (exception.message as? String) ?: "Unable to read error message"
|
|
41
|
-
MPVLib.logMessage("RNLE", 20, message)
|
|
42
|
-
} catch (e: Exception) {
|
|
43
|
-
if (!SWALLOW){
|
|
44
|
-
throw e
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
fun createManagedInstance(): Boolean {
|
|
50
|
-
if(created){ return false }
|
|
51
|
-
try{
|
|
52
|
-
MPVLib.create(applicationContext)
|
|
53
|
-
createMpvDirectory()
|
|
54
|
-
created = true
|
|
55
|
-
return true
|
|
56
|
-
} catch(e:Exception){
|
|
57
|
-
return false
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
fun initNativeBinding() {
|
|
62
|
-
if (destroyed || !created || inited){ return }
|
|
63
|
-
try {
|
|
64
|
-
MPVLib.init()
|
|
65
|
-
inited = true
|
|
66
|
-
} catch (e: Exception) {
|
|
67
|
-
logException(e)
|
|
68
|
-
if (!SWALLOW){
|
|
69
|
-
throw e
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
private fun createMpvDirectory() {
|
|
75
|
-
if (destroyed){ return }
|
|
76
|
-
val mpvDir = File(applicationContext.getExternalFilesDir("mpv"), "mpv")
|
|
77
|
-
try {
|
|
78
|
-
mpvDirectory = mpvDir.absolutePath
|
|
79
|
-
if (!mpvDir.exists() && !mpvDir.mkdirs()) {
|
|
80
|
-
Log.e(TAG, "exception", IllegalArgumentException("Unable to create $mpvDir"))
|
|
81
|
-
return
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// Copy font
|
|
85
|
-
val mpvFontPath = "${mpvDir}/subfont.ttf"
|
|
86
|
-
applicationContext.assets.open("subfont.ttf").use { subfontIn ->
|
|
87
|
-
FileOutputStream(mpvFontPath).use { fontOut ->
|
|
88
|
-
subfontIn.copyTo(fontOut)
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Copy conf
|
|
93
|
-
val mpvConfPath = "${mpvDir}/mpv.conf"
|
|
94
|
-
applicationContext.assets.open("mpv.conf").use { mpvConfIn ->
|
|
95
|
-
FileOutputStream(mpvConfPath).use { confOut ->
|
|
96
|
-
mpvConfIn.copyTo(confOut)
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
} catch (e: Exception) {
|
|
100
|
-
Log.e(TAG, "Unable to create the directory $mpvDir", e)
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
fun addEventObserver(observer: MPVLib.EventObserver) {
|
|
105
|
-
if (destroyed || !created){ return }
|
|
106
|
-
try {
|
|
107
|
-
MPVLib.removeObservers()
|
|
108
|
-
MPVLib.addObserver(observer)
|
|
109
|
-
|
|
110
|
-
MPVLib.observeProperty("demuxer-cache-time", MPVLib.MpvFormat.MPV_FORMAT_DOUBLE)
|
|
111
|
-
MPVLib.observeProperty("duration", MPVLib.MpvFormat.MPV_FORMAT_DOUBLE)
|
|
112
|
-
MPVLib.observeProperty("eof-reached", MPVLib.MpvFormat.MPV_FORMAT_FLAG)
|
|
113
|
-
MPVLib.observeProperty("paused-for-cache", MPVLib.MpvFormat.MPV_FORMAT_FLAG)
|
|
114
|
-
MPVLib.observeProperty("seekable", MPVLib.MpvFormat.MPV_FORMAT_FLAG)
|
|
115
|
-
MPVLib.observeProperty("speed", MPVLib.MpvFormat.MPV_FORMAT_DOUBLE)
|
|
116
|
-
MPVLib.observeProperty("time-pos", MPVLib.MpvFormat.MPV_FORMAT_DOUBLE)
|
|
117
|
-
MPVLib.observeProperty("track-list", MPVLib.MpvFormat.MPV_FORMAT_STRING)
|
|
118
|
-
|
|
119
|
-
} catch (e: Exception) {
|
|
120
|
-
logException(e)
|
|
121
|
-
if (!SWALLOW){
|
|
122
|
-
throw e
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
fun addLogObserver(observer: MPVLib.LogObserver) {
|
|
128
|
-
if (destroyed || !created){ return }
|
|
129
|
-
try {
|
|
130
|
-
MPVLib.removeLogObservers()
|
|
131
|
-
MPVLib.addLogObserver(observer)
|
|
132
|
-
} catch (e: Exception) {
|
|
133
|
-
logException(e)
|
|
134
|
-
if (!SWALLOW) {
|
|
135
|
-
throw e
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
|
|
140
|
-
fun setOptionString(option: String, setting: String) {
|
|
141
|
-
if (destroyed || !created){ return }
|
|
142
|
-
try {
|
|
143
|
-
MPVLib.setOptionString(option, setting)
|
|
144
|
-
} catch (e: Exception) {
|
|
145
|
-
logException(e)
|
|
146
|
-
if (!SWALLOW){
|
|
147
|
-
throw e
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
fun setPropertyString(property: String, setting: String) {
|
|
153
|
-
if (destroyed || !created){ return }
|
|
154
|
-
try {
|
|
155
|
-
MPVLib.setPropertyString(property, setting)
|
|
156
|
-
} catch (e: Exception) {
|
|
157
|
-
logException(e)
|
|
158
|
-
if (!SWALLOW){
|
|
159
|
-
throw e
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
fun command(orders: Array<String>) {
|
|
165
|
-
if (destroyed || !created){ return }
|
|
166
|
-
try {
|
|
167
|
-
MPVLib.command(orders)
|
|
168
|
-
} catch (e: Exception) {
|
|
169
|
-
logException(e)
|
|
170
|
-
if (!SWALLOW){
|
|
171
|
-
throw e
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
fun attachSurface(surfaceView: SurfaceView) {
|
|
177
|
-
if (destroyed || !created){ return }
|
|
178
|
-
try {
|
|
179
|
-
this.surfaceView = surfaceView
|
|
180
|
-
applySurfaceDimensions()
|
|
181
|
-
MPVLib.attachSurface(surfaceView.holder.surface)
|
|
182
|
-
} catch (e: Exception) {
|
|
183
|
-
logException(e)
|
|
184
|
-
if (!SWALLOW){
|
|
185
|
-
throw e
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
fun play(url: String, options: String? = null) {
|
|
191
|
-
if (destroyed) { return }
|
|
192
|
-
if (!isPlaying) {
|
|
193
|
-
if (options == null) {
|
|
194
|
-
command(arrayOf("loadfile", url))
|
|
195
|
-
} else {
|
|
196
|
-
command(arrayOf("loadfile", url, "replace", "0", options))
|
|
197
|
-
}
|
|
198
|
-
command(arrayOf("set", "pause", "no"))
|
|
199
|
-
hasPlayedOnce = true
|
|
200
|
-
isPlaying = true
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
fun pauseOrUnpause() {
|
|
205
|
-
if (destroyed || !hasPlayedOnce){ return }
|
|
206
|
-
if (isPlaying){
|
|
207
|
-
pause()
|
|
208
|
-
} else {
|
|
209
|
-
unpause()
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
fun pause() {
|
|
214
|
-
if (destroyed || !hasPlayedOnce) { return }
|
|
215
|
-
if (isPlaying) {
|
|
216
|
-
command(arrayOf("set", "pause", "yes"))
|
|
217
|
-
isPlaying = false
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
fun unpause() {
|
|
222
|
-
if (destroyed || !hasPlayedOnce) { return }
|
|
223
|
-
if (!isPlaying) {
|
|
224
|
-
command(arrayOf("set", "pause", "no"))
|
|
225
|
-
isPlaying = true
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
fun seekToSeconds(seconds: Int) {
|
|
230
|
-
if (destroyed || !created) { return }
|
|
231
|
-
command(arrayOf("seek", seconds.toString(), "absolute"))
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
private fun applySurfaceDimensions() {
|
|
235
|
-
if (destroyed) { return }
|
|
236
|
-
if (surfaceHeight != -1 && surfaceWidth != -1 && surfaceView != null) {
|
|
237
|
-
surfaceView?.holder?.setFixedSize(surfaceWidth, surfaceHeight)
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
fun setSurfaceWidth(width: Int) {
|
|
242
|
-
if (destroyed) { return }
|
|
243
|
-
surfaceWidth = width
|
|
244
|
-
applySurfaceDimensions()
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
fun setSurfaceHeight(height: Int) {
|
|
248
|
-
if (destroyed) { return }
|
|
249
|
-
surfaceHeight = height
|
|
250
|
-
applySurfaceDimensions()
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
fun detachSurface(){
|
|
254
|
-
if(destroyed) { return }
|
|
255
|
-
try{
|
|
256
|
-
MPVLib.detachSurface()
|
|
257
|
-
}
|
|
258
|
-
catch(e:Exception){
|
|
259
|
-
logException(e)
|
|
260
|
-
if(!SWALLOW){
|
|
261
|
-
throw e
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
fun cleanup() {
|
|
268
|
-
if (!created || cleaning)
|
|
269
|
-
{
|
|
270
|
-
return
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
cleaning = true
|
|
274
|
-
|
|
275
|
-
try {
|
|
276
|
-
command(arrayOf("stop"))
|
|
277
|
-
setPropertyString("pause", "yes")
|
|
278
|
-
setPropertyString("vo", "null")
|
|
279
|
-
setPropertyString("ao", "null")
|
|
280
|
-
detachSurface()
|
|
281
|
-
Handler(Looper.getMainLooper()).post {
|
|
282
|
-
MPVLib.removeObservers()
|
|
283
|
-
MPVLib.removeLogObservers()
|
|
284
|
-
MPVLib.destroy()
|
|
285
|
-
created = false
|
|
286
|
-
cleaning = false
|
|
287
|
-
}
|
|
288
|
-
} catch (e: Exception) {
|
|
289
|
-
logException(e)
|
|
290
|
-
cleaning = false
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
|
|
294
|
-
fun destroy(){
|
|
295
|
-
return cleanup()
|
|
296
|
-
}
|
|
297
|
-
}
|