Format stuff

This commit is contained in:
2026-04-20 12:13:36 +02:00
parent 3423be6736
commit 4bb13739d5
6 changed files with 76 additions and 49 deletions
@@ -10,9 +10,9 @@ import android.os.SystemClock
import dev.jdtech.mpv.MPVLib
class EventMap(private val player: MPVLib) : HybridOmniEventMapSpec(), MPVLib.EventObserver {
val onPrevListeners = mutableSetOf<() -> Unit>()
val onNextListeners = mutableSetOf<() -> Unit>()
private val onEndListeners = mutableSetOf<() -> Unit>()
private val onPrevListeners = mutableSetOf<() -> Unit>()
private val onNextListeners = mutableSetOf<() -> Unit>()
private val onErrorListeners = mutableSetOf<(type: String, message: String) -> Unit>()
private val onAudioFocusChangeListeners = mutableSetOf<(status: String) -> Unit>()
private val onVideoTrackChangeListeners = mutableSetOf<(track: Track) -> Unit>()
@@ -32,7 +32,7 @@ class EventMap(private val player: MPVLib) : HybridOmniEventMapSpec(), MPVLib.Ev
player.observeProperty("aid", MPVLib.MpvFormat.MPV_FORMAT_INT64)
player.observeProperty("sid", MPVLib.MpvFormat.MPV_FORMAT_INT64)
player.observeProperty("pause", MPVLib.MpvFormat.MPV_FORMAT_FLAG)
player.observeProperty("muted", MPVLib.MpvFormat.MPV_FORMAT_FLAG)
player.observeProperty("mute", MPVLib.MpvFormat.MPV_FORMAT_FLAG)
player.observeProperty("eof-reached", MPVLib.MpvFormat.MPV_FORMAT_FLAG)
player.observeProperty("core-idle", MPVLib.MpvFormat.MPV_FORMAT_FLAG)
player.observeProperty("paused-for-cache", MPVLib.MpvFormat.MPV_FORMAT_FLAG)
@@ -65,7 +65,12 @@ class EventMap(private val player: MPVLib) : HybridOmniEventMapSpec(), MPVLib.Ev
val label = player.getPropertyString("$base/title")
?: player.getPropertyString("$base/codec")
val language = player.getPropertyString("$base/lang")
return Track(id = trackId.toString(), label = label, language = language, selected = selected)
return Track(
id = trackId.toString(),
label = label,
language = language,
selected = selected
)
}
return null
}
@@ -78,8 +83,10 @@ class EventMap(private val player: MPVLib) : HybridOmniEventMapSpec(), MPVLib.Ev
isSeeking = false
playerStatusListeners.forEach { it(PlayerStatus.LOADING) }
}
MPVLib.MpvEvent.MPV_EVENT_FILE_LOADED ->
playerStatusListeners.forEach { it(PlayerStatus.READYTOPLAY) }
MPVLib.MpvEvent.MPV_EVENT_SEEK -> isSeeking = true
MPVLib.MpvEvent.MPV_EVENT_PLAYBACK_RESTART -> isSeeking = false
MPVLib.MpvEvent.MPV_EVENT_END_FILE -> {
@@ -93,6 +100,7 @@ class EventMap(private val player: MPVLib) : HybridOmniEventMapSpec(), MPVLib.Ev
}
playerStatusListeners.forEach { it(PlayerStatus.IDLE) }
}
MPVLib.MpvEvent.MPV_EVENT_QUEUE_OVERFLOW -> onErrorListeners.forEach {
it("queue_overflow", "mpv event queue overflow")
}
@@ -107,10 +115,12 @@ class EventMap(private val player: MPVLib) : HybridOmniEventMapSpec(), MPVLib.Ev
val track = getTrackById("video", value)
if (track != null) onVideoTrackChangeListeners.forEach { it(track) }
}
"aid" -> {
val track = getTrackById("audio", value)
if (track != null) onAudioTrackChangeListeners.forEach { it(track) }
}
"sid" -> {
val track = getTrackById("sub", value)
onSubtitleChangeListeners.forEach { it(track) }
@@ -124,12 +134,16 @@ class EventMap(private val player: MPVLib) : HybridOmniEventMapSpec(), MPVLib.Ev
lastTimePosDispatchMs = SystemClock.elapsedRealtime()
stateListeners[NumberProperty.CURRENTTIME]?.forEach { it(value.coerceAtLeast(0.0)) }
}
"demuxer-cache-time" -> stateListeners[NumberProperty.BUFFERED]
?.forEach { it(value.coerceAtLeast(0.0)) }
"duration" -> stateListeners[NumberProperty.DURATION]
?.forEach { it(value.coerceAtLeast(0.0)) }
"speed" -> stateListeners[NumberProperty.PLAYBACKRATE]
?.forEach { it(value) }
"volume" -> stateListeners[NumberProperty.VOLUME]
?.forEach { it((value / 100.0).coerceIn(0.0, 1.0)) }
}
@@ -142,8 +156,10 @@ class EventMap(private val player: MPVLib) : HybridOmniEventMapSpec(), MPVLib.Ev
onAudioFocusChangeListeners.forEach { it(if (isPlaying) "playing" else "paused") }
stateBoolListeners[BoolProperty.ISPLAYING]?.forEach { it(isPlaying) }
}
"muted" ->
"mute" ->
stateBoolListeners[BoolProperty.MUTED]?.forEach { it(value) }
"eof-reached" -> eofReached = value
"core-idle", "paused-for-cache" ->
playerStatusListeners.forEach { it(computePlayerStatus()) }
@@ -12,8 +12,9 @@ import com.margelo.nitro.omni.views.*;
public class OmniPackage : BaseReactPackage() {
override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? = null
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider = ReactModuleInfoProvider { emptyMap() }
override fun getReactModuleInfoProvider(): ReactModuleInfoProvider =
ReactModuleInfoProvider { emptyMap() }
override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
val viewManagers = ArrayList<ViewManager<*, *>>()
viewManagers.add(HybridOmniViewManager())
@@ -1,5 +1,6 @@
package dev.zoriya.omni
import android.util.Log
import com.margelo.nitro.NitroModules
import com.margelo.nitro.omni.Source
import com.margelo.nitro.omni.HybridOmniPlayerSpec
@@ -15,7 +16,7 @@ class OmniPlayer : HybridOmniPlayerSpec() {
override val eventMap = EventMap(player)
init {
player.setOptionString("vo", "gpu")
player.setOptionString("vo", "null")
player.setOptionString("gpu-context", "android")
player.setOptionString("opengl-es", "yes")
player.setOptionString("hwdec", "mediacodec-copy")
@@ -65,43 +66,48 @@ class OmniPlayer : HybridOmniPlayerSpec() {
fun setSurface(surface: android.view.Surface?) {
if (surface == null) {
player.setOptionString("vo", "null")
player.setOptionString("force-window", "no")
player.detachSurface()
} else {
player.attachSurface(surface)
player.setOptionString("force-window", "yes")
player.setOptionString("vo", "gpu-next")
}
}
override val hasPrev get() = source.metadata?.hasPrev ?: false
override val hasNext get() = source.metadata?.hasNext ?: false
override val status: PlayerStatus
get() {
val idle = player.getPropertyBoolean("core-idle") ?: false
val loading = player.getPropertyBoolean("paused-for-cache") ?: false
return when {
idle -> PlayerStatus.IDLE
loading -> PlayerStatus.LOADING
else -> PlayerStatus.READYTOPLAY
}
}
override val status: PlayerStatus
get() {
val idle = player.getPropertyBoolean("core-idle") ?: false
val loading = player.getPropertyBoolean("paused-for-cache") ?: false
return when {
idle -> PlayerStatus.IDLE
loading -> PlayerStatus.LOADING
else -> PlayerStatus.READYTOPLAY
}
}
override val isPlaying get() = !(player.getPropertyBoolean("pause") ?: true)
override var currentTime
get() = (player.getPropertyDouble("time-pos") ?: 0.0).coerceAtLeast(0.0)
set(value) {
player.command(arrayOf("seek", value.coerceAtLeast(0.0).toString(), "absolute"))
}
override val buffered get() = (player.getPropertyDouble("demuxer-cache-time") ?: 0.0).coerceAtLeast(0.0)
get() = (player.getPropertyDouble("time-pos") ?: 0.0).coerceAtLeast(0.0)
set(value) {
player.command(arrayOf("seek", value.coerceAtLeast(0.0).toString(), "absolute"))
}
override val buffered
get() = (player.getPropertyDouble("demuxer-cache-time") ?: 0.0).coerceAtLeast(0.0)
override val duration get() = (player.getPropertyDouble("duration") ?: 0.0).coerceAtLeast(0.0)
override var playbackRate
get() = player.getPropertyDouble("speed") ?: 1.0
set(value) {
player.setPropertyDouble("speed", value.coerceAtLeast(0.0))
}
}
override var muted
get() = player.getPropertyBoolean("muted") ?: false
get() = player.getPropertyBoolean("mute") ?: false
set(value) {
player.setPropertyBoolean("muted", value)
player.setPropertyBoolean("mute", value)
}
override var volume
get() = (player.getPropertyDouble("volume") ?: 100.0).coerceIn(0.0, 100.0) / 100.0
@@ -128,32 +134,32 @@ class OmniPlayer : HybridOmniPlayerSpec() {
}
override fun playPrev() {
// App-level action; no default implementation in VLC player.
eventMap.onPrevListeners.forEach { it() }
}
override fun playNext() {
// App-level action; no default implementation in VLC player.
eventMap.onNextListeners.forEach { it() }
}
override fun selectVideo(video: Track) {
val id = video.id.toIntOrNull() ?: return
player.setPropertyInt("vid", id)
}
override fun selectVideo(video: Track) {
val id = video.id.toIntOrNull() ?: return
player.setPropertyInt("vid", id)
}
override fun selectAudio(audio: Track) {
val id = audio.id.toIntOrNull() ?: return
player.setPropertyInt("aid", id)
}
override fun selectAudio(audio: Track) {
val id = audio.id.toIntOrNull() ?: return
player.setPropertyInt("aid", id)
}
override fun selectSubtitle(subtitle: Track?) {
when (subtitle) {
null -> player.setPropertyString("sid", "no")
else -> {
val id = subtitle.id.toIntOrNull() ?: return
player.setPropertyInt("sid", id)
}
}
}
override fun selectSubtitle(subtitle: Track?) {
when (subtitle) {
null -> player.setPropertyString("sid", "no")
else -> {
val id = subtitle.id.toIntOrNull() ?: return
player.setPropertyInt("sid", id)
}
}
}
override fun selectRendition(rendition: Rendition?) {
// Not supported by libVLC MediaPlayer track APIs.
@@ -5,7 +5,7 @@ import com.margelo.nitro.omni.HybridOmniPlayerFactorySpec
import com.margelo.nitro.omni.HybridOmniPlayerSpec
import com.margelo.nitro.omni.Source
class OmniPlayerFactory(val context: ThemedReactContext): HybridOmniPlayerFactorySpec() {
class OmniPlayerFactory(val context: ThemedReactContext) : HybridOmniPlayerFactorySpec() {
override fun createPlayer(props: Source): HybridOmniPlayerSpec {
return OmniPlayer().apply {
source = props
@@ -26,7 +26,12 @@ class OmniView(val context: ThemedReactContext) : HybridOmniViewSpec() {
boundPlayer?.setSurface(holder.surface)
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
override fun surfaceChanged(
holder: SurfaceHolder,
format: Int,
width: Int,
height: Int
) {
surfaceReady = true
boundPlayer?.setSurface(holder.surface)
}
+1 -2
View File
@@ -5,8 +5,7 @@ import type { OmniEvents } from "./types/events";
import type { OmniPlayerState } from "./types/player";
function capitalize<T extends string>(str: T): Capitalize<T> {
return (str.charAt(0).toUpperCase() +
str.slice(1).toLowerCase()) as Capitalize<T>;
return (str.charAt(0).toUpperCase() + str.slice(1)) as Capitalize<T>;
}
export const useEvent = <Event extends keyof OmniEvents>(