forked from mpv-android/mpv-android
-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathBaseMPVView.kt
109 lines (88 loc) · 3.3 KB
/
BaseMPVView.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
package `is`.xyz.mpv
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.SurfaceHolder
import android.view.SurfaceView
// Contains only the essential code needed to get a picture on the screen
abstract class BaseMPVView(context: Context, attrs: AttributeSet) : SurfaceView(context, attrs), SurfaceHolder.Callback {
/**
* Initialize libmpv.
*
* Call this once before the view is shown.
*/
fun initialize(configDir: String, cacheDir: String, logLvl: String = "v", vo: String = "gpu") {
MPVLib.create(context, logLvl)
/* set normal options (user-supplied config can override) */
MPVLib.setOptionString("config", "yes")
MPVLib.setOptionString("config-dir", configDir)
for (opt in arrayOf("gpu-shader-cache-dir", "icc-cache-dir"))
MPVLib.setOptionString(opt, cacheDir)
initOptions(vo)
MPVLib.init()
/* set hardcoded options */
postInitOptions()
// would crash before the surface is attached
MPVLib.setOptionString("force-window", "no")
// need to idle at least once for playFile() logic to work
MPVLib.setOptionString("idle", "once")
holder.addCallback(this)
observeProperties()
}
/**
* Deinitialize libmpv.
*
* Call this once before the view is destroyed.
*/
fun destroy() {
// Disable surface callbacks to avoid using unintialized mpv state
holder.removeCallback(this)
MPVLib.destroy()
}
protected abstract fun initOptions(vo: String)
protected abstract fun postInitOptions()
protected abstract fun observeProperties()
private var filePath: String? = null
/**
* Set the first file to be played once the player is ready.
*/
fun playFile(filePath: String) {
this.filePath = filePath
}
private var voInUse: String = ""
/**
* Sets the VO to use.
* It is automatically disabled/enabled when the surface dis-/appears.
*/
fun setVo(vo: String) {
voInUse = vo
MPVLib.setOptionString("vo", vo)
}
// Surface callbacks
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
MPVLib.setPropertyString("android-surface-size", "${width}x$height")
}
override fun surfaceCreated(holder: SurfaceHolder) {
Log.w(TAG, "attaching surface")
MPVLib.attachSurface(holder.surface)
// This forces mpv to render subs/osd/whatever into our surface even if it would ordinarily not
MPVLib.setOptionString("force-window", "yes")
if (filePath != null) {
MPVLib.command(arrayOf("loadfile", filePath as String))
filePath = null
} else {
// We disable video output when the context disappears, enable it back
MPVLib.setPropertyString("vo", voInUse)
}
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
Log.w(TAG, "detaching surface")
MPVLib.setPropertyString("vo", "null")
MPVLib.setOptionString("force-window", "no")
MPVLib.detachSurface()
// FIXME: race condition here because detachSurface just sets a property and that is async
}
companion object {
private const val TAG = "mpv"
}
}