mirror of
https://github.com/zoriya/react-native-omni.git
synced 2026-08-16 02:44:51 +00:00
fix(vlc): stale video surface
This commit is contained in:
@@ -244,6 +244,7 @@ class OmniView(val context: ThemedReactContext) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||||
|
if (isPlaying) scheduleVideoRebuild()
|
||||||
updatePictureInPictureParams()
|
updatePictureInPictureParams()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,22 +378,16 @@ class OmniView(val context: ThemedReactContext) :
|
|||||||
movedSurfaceToRootForPip = false
|
movedSurfaceToRootForPip = false
|
||||||
}
|
}
|
||||||
|
|
||||||
// A surface that is destroyed and recreated while playback runs (the PIP
|
private val rebuildRunnable = Runnable { boundPlayer?.rebuildVideoOutput() }
|
||||||
// reparent) makes VLC drop its video pipeline; it won't rebuild it for the
|
|
||||||
// new surface on its own, so we must ask it to. The rebuild only succeeds
|
private fun scheduleVideoRebuild() {
|
||||||
// once the (PIP) window has settled at its final size — firing it mid-resize
|
surfaceView.removeCallbacks(rebuildRunnable)
|
||||||
// leaves the vout stopped — so it is debounced off surfaceChanged.
|
surfaceView.postDelayed(rebuildRunnable, 200)
|
||||||
private var pendingVideoRebuild = false
|
|
||||||
private val rebuildRunnable = Runnable {
|
|
||||||
if (!pendingVideoRebuild) return@Runnable
|
|
||||||
pendingVideoRebuild = false
|
|
||||||
boundPlayer?.rebuildVideoOutput()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun surfaceCreated(holder: SurfaceHolder) {
|
override fun surfaceCreated(holder: SurfaceHolder) {
|
||||||
surfaceReady = true
|
surfaceReady = true
|
||||||
boundPlayer?.setVideoView(surfaceView)
|
boundPlayer?.setVideoView(surfaceView)
|
||||||
if (boundPlayer?.localPlayer?.isPlaying == true) pendingVideoRebuild = true
|
|
||||||
updatePictureInPictureParams()
|
updatePictureInPictureParams()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -403,10 +398,7 @@ class OmniView(val context: ThemedReactContext) :
|
|||||||
height: Int
|
height: Int
|
||||||
) {
|
) {
|
||||||
boundPlayer?.updateVideoLayout(width, height)
|
boundPlayer?.updateVideoLayout(width, height)
|
||||||
if (pendingVideoRebuild) {
|
scheduleVideoRebuild()
|
||||||
surfaceView.removeCallbacks(rebuildRunnable)
|
|
||||||
surfaceView.postDelayed(rebuildRunnable, 200)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
override fun surfaceDestroyed(holder: SurfaceHolder) {
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ class VlcPlayer(ctx: Context) :
|
|||||||
@Volatile
|
@Volatile
|
||||||
private var cachedBufferedPosition: Long = 0L
|
private var cachedBufferedPosition: Long = 0L
|
||||||
private var boundSurfaceView: SurfaceView? = null
|
private var boundSurfaceView: SurfaceView? = null
|
||||||
|
private var videoOutputStale = false
|
||||||
private var lastVideoSize: VideoSize = VideoSize.UNKNOWN
|
private var lastVideoSize: VideoSize = VideoSize.UNKNOWN
|
||||||
|
|
||||||
private val availableCommands: Player.Commands = Player.Commands.Builder()
|
private val availableCommands: Player.Commands = Player.Commands.Builder()
|
||||||
@@ -348,6 +349,7 @@ class VlcPlayer(ctx: Context) :
|
|||||||
playerError = null
|
playerError = null
|
||||||
|
|
||||||
player.stop()
|
player.stop()
|
||||||
|
videoOutputStale = false
|
||||||
|
|
||||||
mediaItems.getOrNull(targetIndex)?.let { item ->
|
mediaItems.getOrNull(targetIndex)?.let { item ->
|
||||||
val uri = item.localConfiguration?.uri?.toString()
|
val uri = item.localConfiguration?.uri?.toString()
|
||||||
@@ -897,30 +899,22 @@ class VlcPlayer(ctx: Context) :
|
|||||||
if (surfaceView == null) return clearVideoSurface()
|
if (surfaceView == null) return clearVideoSurface()
|
||||||
if (vlcVout.areViewsAttached() && boundSurfaceView === surfaceView) return
|
if (vlcVout.areViewsAttached() && boundSurfaceView === surfaceView) return
|
||||||
boundSurfaceView = surfaceView
|
boundSurfaceView = surfaceView
|
||||||
// Hand VLC the SurfaceView (not a raw Surface) so it reads the real view
|
videoOutputStale = (
|
||||||
// size and keeps the video layout correct as the surface resizes (e.g. the
|
player.playerState == IMedia.State.Playing ||
|
||||||
// PIP window shrinking/growing); see updateVideoLayout for size updates.
|
player.playerState == IMedia.State.Paused
|
||||||
|
)
|
||||||
vlcVout.setVideoView(surfaceView)
|
vlcVout.setVideoView(surfaceView)
|
||||||
vlcVout.attachViews()
|
vlcVout.attachViews()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* VLC tears down its video decoder + output whenever the output Surface is
|
|
||||||
* destroyed (e.g. the SurfaceView being reparented for PIP) and does not
|
|
||||||
* rebuild them when a new Surface arrives — the picture stays black. Toggling
|
|
||||||
* the video track forces VLC to spin up a fresh decoder/vout against the
|
|
||||||
* currently-attached Surface. Safe no-op when nothing is attached/playing.
|
|
||||||
*/
|
|
||||||
fun rebuildVideoOutput() {
|
fun rebuildVideoOutput() {
|
||||||
if (!vlcVout.areViewsAttached() || !player.isPlaying) return
|
if (!videoOutputStale || !player.isPlaying || !vlcVout.areViewsAttached()) return
|
||||||
|
videoOutputStale = false
|
||||||
player.setVideoTrackEnabled(false)
|
player.setVideoTrackEnabled(false)
|
||||||
player.setVideoTrackEnabled(true)
|
player.setVideoTrackEnabled(true)
|
||||||
player.updateVideoSurfaces()
|
player.updateVideoSurfaces()
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Recompute the video layout for the current surface size. Must run whenever
|
|
||||||
* the surface resizes (VLC latches a stale geometry otherwise -> the picture
|
|
||||||
* renders at the wrong size, anchored in a corner). */
|
|
||||||
fun updateVideoLayout(width: Int, height: Int) {
|
fun updateVideoLayout(width: Int, height: Int) {
|
||||||
if (!vlcVout.areViewsAttached()) return
|
if (!vlcVout.areViewsAttached()) return
|
||||||
if (width > 0 && height > 0) vlcVout.setWindowSize(width, height)
|
if (width > 0 && height > 0) vlcVout.setWindowSize(width, height)
|
||||||
|
|||||||
Reference in New Issue
Block a user