Browse Source

Distinguish TextureView update notifications from committed frames

master
evgeny 4 days ago
parent
commit
d7788b87ac
  1. 4
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoPlayer.kt
  2. 27
      tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/CallVideoPanel.kt

4
tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoPlayer.kt

@ -123,10 +123,10 @@ internal class CallVideoPlayer(private val id: Long, private val failure: (Strin
decoder = MediaCodec.createByCodecName(implementation.name)
decoder!!.configure(type.decoderFormat(next.width, next.height, next.rotation, config), surface, null, 0)
decoder!!.setOnFrameRenderedListener({ _, pts, at ->
// Время события, а не доставки callback: Android может группировать уведомления.
// На некоторых SurfaceTexture backend at повторяет PTS: логируем как reported, не как доказанное время показа.
if (running && pts % 1_000_000 < 34_000) LogManager.addLog("DEBUG", "debug",
"video timing stage=surface call=$id generation=${next.generation} pts=$pts " +
"mono_us=${at / 1000} callback_us=${System.nanoTime() / 1000}")
"reported_us=${at / 1000} callback_us=${System.nanoTime() / 1000}")
}, renderHandler)
decoder!!.start(); format = next; lastProgress = now
LogManager.addLog("INFO", "call", "video decoder started call=$id codec=${implementation.name} format=$next")

27
tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/CallVideoPanel.kt

@ -5,6 +5,7 @@ import android.content.pm.PackageManager
import android.content.Context
import android.graphics.Matrix
import android.graphics.SurfaceTexture
import android.os.Build
import android.view.Surface
import android.view.TextureView
import androidx.activity.compose.rememberLauncherForActivityResult
@ -128,6 +129,19 @@ private class CallVideoTexture(context: Context, private val video: CallVideoEng
private var closed = false
private var format: CallVideoFormat? = null
private var large = false
private var commitPending = false
private var lastCommitPts = -1L
private val committed = Runnable {
commitPending = false
if (!closed) surfaceTexture?.let { texture ->
val pts = texture.timestamp / 1000
if (pts > 0 && pts != lastCommitPts && pts % 1_000_000 < 34_000)
com.utun.chat.data.LogManager.addLog("DEBUG", "debug",
"video timing stage=commit pts=$pts mono_us=${System.nanoTime() / 1000} generation=${format?.generation} " +
"visible=$isShown alpha=$alpha size=${width}x$height")
lastCommitPts = pts
}
}
fun update(next: CallVideoFormat?, expanded: Boolean) {
if (format == next && large == expanded) return
format = next; large = expanded; fit()
@ -144,11 +158,14 @@ private class CallVideoTexture(context: Context, private val video: CallVideoEng
override fun onSurfaceTextureSizeChanged(texture: SurfaceTexture, width: Int, height: Int) { fit() }
override fun onSurfaceTextureDestroyed(texture: SurfaceTexture): Boolean { closeOutput(); return false }
override fun onSurfaceTextureUpdated(texture: SurfaceTexture) {
// MediaCodec передаёт исходный PTS в SurfaceTexture; не вычитаем его из локальных часов телефона.
// applyUpdate лишь передаёт работу RenderThread: timestamp здесь ещё может принадлежать предыдущему кадру.
val pts = texture.timestamp / 1000
if (pts > 0 && pts % 1_000_000 < 34_000) com.utun.chat.data.LogManager.addLog("DEBUG", "debug",
"video timing stage=texture pts=$pts mono_us=${System.nanoTime() / 1000} generation=${format?.generation} " +
"video timing stage=texture_update pts=$pts mono_us=${System.nanoTime() / 1000} generation=${format?.generation} " +
"visible=$isShown alpha=$alpha size=${width}x$height")
if (Build.VERSION.SDK_INT >= 29 && isHardwareAccelerated && !commitPending) {
commitPending = true; viewTreeObserver.registerFrameCommitCallback(committed)
}
}
}
}
@ -168,7 +185,11 @@ private class CallVideoTexture(context: Context, private val video: CallVideoEng
com.utun.chat.data.LogManager.addLog("DEBUG", "call", "video fit view=${width}x$height frame=${w}x$h expanded=$large turn=$turn")
}
private fun closeOutput() { attached?.let(video::detachSurface); attached = null }
fun close() { closed = true; closeOutput() }
fun close() {
closed = true
if (Build.VERSION.SDK_INT >= 29 && viewTreeObserver.isAlive) viewTreeObserver.unregisterFrameCommitCallback(committed)
closeOutput()
}
}
@Composable

Loading…
Cancel
Save