Browse Source

Bound Android bitrate wait by requested keyframe cadence

master
evgeny 4 days ago
parent
commit
5666da8859
  1. 16
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoEngine.kt

16
tools/chatgui-android/app/src/main/java/com/utun/chat/data/CallVideoEngine.kt

@ -56,7 +56,7 @@ class CallVideoEngine(private val context: Context, private val id: Long) {
private var generation = 0L
private var frame = 0L
private var lastPts = -1L
private var lastKey = -1L
private var lastKeyRequest = -1L
private var keySerial = -1L
private var needKey = true
private var request = 0L
@ -151,6 +151,7 @@ class CallVideoEngine(private val context: Context, private val id: Long) {
}
if (s[1] == format?.generation && s[2] > request) {
request = s[2]; pendingRequest = request; pendingRate = s[3].toInt()
LogManager.addLog("DEBUG", "call", "video bitrate queued id=$id request=$request target=$pendingRate lastKeyRequest=$lastKeyRequest")
}
if (!wanted.enabled) {
if (active != null) {
@ -159,7 +160,7 @@ class CallVideoEngine(private val context: Context, private val id: Long) {
confirmingRequest = 0; pendingRequest = 0
closeCamera(); encoder?.close(); encoder = null; active = null; report("Video off")
}
} else if (wanted != active && !opening && !closing && (lastKey < 0 || System.nanoTime() / 1000 - lastKey >= 1_000_000)) {
} else if (wanted != active && !opening && !closing && (lastKeyRequest < 0 || System.nanoTime() / 1000 - lastKeyRequest >= 1_000_000)) {
val peer = CallVideoNative.peer(id)
if (peer != null) change(peer)
}
@ -190,7 +191,7 @@ class CallVideoEngine(private val context: Context, private val id: Long) {
check(CallVideoNative.supported(caps, peer, next.array())) { "Actual encoder format exceeds peer capabilities: $next" }
check(CallVideoNative.format(id, next.array(), candidate.bitrate)) { "Video format rejected" }
closeCamera(); encoder = candidate; format = next; active = wanted
pendingRequest = 0; confirmingRequest = 0; request = 0; lastKey = -1; needKey = true
pendingRequest = 0; confirmingRequest = 0; request = 0; lastKeyRequest = -1; needKey = true
mutable.value = mutable.value.copy(bitrate = candidate.bitrate)
if (!closing) openCamera()
return
@ -229,7 +230,8 @@ class CallVideoEngine(private val context: Context, private val id: Long) {
val pts = (image.timestamp + offset) / 1000
// Camera2 уже ограничена 30 fps. Порог 33333 мкс отбрасывал каждый второй кадр при дрожании часов.
if (pts <= lastPts) return@setOnImageAvailableListener
val key = needKey || confirmingRequest != 0L || lastKey < 0 || pts - lastKey >= 1_000_000
// Автоматический IDR кодека не переносит нашу границу: иначе смена bitrate может ждать бесконечно.
val key = needKey || confirmingRequest != 0L || lastKeyRequest < 0 || pts - lastKeyRequest >= 1_000_000
if (key && pendingRequest != 0L) {
val requestId = pendingRequest; pendingRequest = 0
val old = checkNotNull(encoder); val oldRate = old.bitrate; val name = old.name
@ -252,7 +254,10 @@ class CallVideoEngine(private val context: Context, private val id: Long) {
}
}
}
if (encoder?.submit(image, pts, key) == true) lastPts = pts
if (encoder?.submit(image, pts, key) == true) {
lastPts = pts
if (key) lastKeyRequest = pts
}
drain()
} catch (e: Exception) { fail("Camera encode: ${e.message}") }
finally { image.close() }
@ -335,7 +340,6 @@ class CallVideoEngine(private val context: Context, private val id: Long) {
val codec = encoder ?: return; val f = format ?: return
for (p in codec.drain()) {
encodedBytes += p.bytes.size; encodedFrames++
if (p.key) lastKey = p.pts
if (confirmingRequest != 0L && p.key && p.pts >= confirmingPts) {
CallVideoNative.applied(id, f.generation, confirmingRequest, codec.bitrate); confirmingRequest = 0
mutable.value = mutable.value.copy(bitrate = codec.bitrate)

Loading…
Cancel
Save