Keep preview layout stable and document codec configuration exchange

This commit is contained in:
evgeny committed 2026-10-14 01:56:02 +02:00
1 parent 39297d1a07
commit b4aeb1a3fd
3 files changed
+30 -20

No files matched your search

@@ -162,7 +162,7 @@ class StreamCaptureEngine(
var problem: String? = null
try {
if (info.size > 0) {
val buffer = codec.getOutputBuffer(index) ?: error("Missing AVC output")
val buffer = codec.getOutputBuffer(index) ?: error("Missing video encoder output")
buffer.position(info.offset); buffer.limit(info.offset + info.size)
val bytes = ByteArray(info.size).also { buffer.get(it) }
if (info.flags and MediaCodec.BUFFER_FLAG_CODEC_CONFIG != 0) {
@@ -271,14 +271,14 @@ class StreamCaptureEngine(
private fun encoded(bytes: ByteArray, info: MediaCodec.BufferInfo, config: StreamCaptureConfig, rotation: Int, revision: Long) {
val mode = config.mode
if (partial.size() == 0) { partialPts = info.presentationTimeUs; partialKey = false }
check(info.presentationTimeUs == partialPts) { "Partial AVC frame PTS changed" }
check(partial.size() + bytes.size <= H264AnnexB.MAX_FRAME) { "AVC frame exceeds limit" }
check(info.presentationTimeUs == partialPts) { "Partial video frame PTS changed" }
check(partial.size() + bytes.size <= H264AnnexB.MAX_FRAME) { "Video frame exceeds limit" }
partial.write(bytes); partialKey = partialKey || info.flags and MediaCodec.BUFFER_FLAG_KEY_FRAME != 0
if (info.flags and MediaCodec.BUFFER_FLAG_PARTIAL_FRAME != 0) return
val data = mode.videoCodec.normalize(partial.toByteArray()); partial.reset()
val key = partialKey
val pts = partialPts - originNs / 1000
check(pts >= 0 && pts > lastPts) { "AVC PTS outside timeline pts=$pts last=$lastPts" }
check(pts >= 0 && pts > lastPts) { "Video PTS outside timeline pts=$pts last=$lastPts" }
lastPts = pts; encodedFrames++
if (requireKey && !key) { dropped++; requestKey() }
else {
@@ -329,7 +329,7 @@ class StreamCaptureEngine(
if (now - lastKeyRequest < 500_000_000) return
lastKeyRequest = now
encoder?.setParameters(Bundle().apply { putInt(MediaCodec.PARAMETER_KEY_REQUEST_SYNC_FRAME, 0) })
LogManager.addLog("INFO", "video", "requested AVC keyframe id=$id revision=$generation")
LogManager.addLog("INFO", "video", "requested video keyframe id=$id encoder=${encoder?.name} revision=$generation")
}
/** Новая камера открывается только после onClosed; старые codec callbacks уже отсечены. */
@@ -173,9 +173,9 @@ private fun StreamTxPanel(id: Long) {
val s = snapshot?.takeIf { it.id == id } ?: return
Column {
Text(stringResource(R.string.stream_tx_queues, s.videoBytes / 1024.0, s.inflightBytes / 1024.0),
style = MaterialTheme.typography.bodySmall)
style = MaterialTheme.typography.bodySmall, minLines = 2)
Text(stringResource(R.string.stream_tx_total, s.totalBytes / 1024.0, s.acked1s / 1024.0, s.acked1s * 8 / 1_000_000.0),
style = MaterialTheme.typography.bodySmall)
style = MaterialTheme.typography.bodySmall, minLines = 2)
}
}