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