From 06bd9947ce21a105b2adbc8ea06b9fd4de34a157 Mon Sep 17 00:00:00 2001 From: evgeny Date: Wed, 14 Oct 2026 01:21:04 +0200 Subject: [PATCH] Test codec keyframes and bitrate selection across camera changes --- .../utun/chat/data/StreamVideoCodecTest.kt | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 tools/chatgui-android/app/src/test/java/com/utun/chat/data/StreamVideoCodecTest.kt diff --git a/tools/chatgui-android/app/src/test/java/com/utun/chat/data/StreamVideoCodecTest.kt b/tools/chatgui-android/app/src/test/java/com/utun/chat/data/StreamVideoCodecTest.kt new file mode 100644 index 00000000..5e27a8ec --- /dev/null +++ b/tools/chatgui-android/app/src/test/java/com/utun/chat/data/StreamVideoCodecTest.kt @@ -0,0 +1,32 @@ +package com.utun.chat.data + +import org.junit.Assert.* +import org.junit.Test + +class StreamVideoCodecTest { + private fun nal(vararg bytes: Int) = byteArrayOf(0, 0, 0, 1) + bytes.map { it.toByte() }.toByteArray() + @Test fun everyCodecCarriesConfigurationWithKey() { + val configs = listOf(nal(0x67, 1) + nal(0x68, 2), nal(64, 1) + nal(66, 1) + nal(68, 1), + byteArrayOf(1, 2), byteArrayOf(3, 4), nal(0, 121) + nal(0, 129)) + val frames = listOf(nal(0x65, 3), nal(38, 1), byteArrayOf(5, 6), byteArrayOf(7, 8), nal(0, 57)) + StreamVideoCodec.values().forEachIndexed { i, codec -> + val packet = codec.keyFrame(frames[i], configs[i]); val decoded = codec.unpackKey(packet) + assertArrayEquals(configs[i], decoded.first); assertArrayEquals(frames[i], decoded.second) + assertEquals(codec, StreamVideoCodec.fromId(i + 1)) + } + } + @Test fun malformedConfigurationIsRejected() { + for (size in 0..4) assertThrows(IllegalArgumentException::class.java) { StreamVideoCodec.VP9.unpackKey(ByteArray(size)) } + assertThrows(IllegalArgumentException::class.java) { StreamVideoCodec.AV1.unpackKey(byteArrayOf(0, 1, 0, 1, 1)) } + assertThrows(IllegalArgumentException::class.java) { StreamVideoCodec.H264.keyFrame(nal(0x41, 1), byteArrayOf()) } + val decoded = StreamVideoCodec.VP9.unpackKey(StreamVideoCodec.VP9.keyFrame(byteArrayOf(1), byteArrayOf())) + assertTrue(decoded.first.isEmpty()); assertArrayEquals(byteArrayOf(1), decoded.second) + } + @Test fun codecAndBitrateSurviveCameraModeSelection() { + val base = StreamCaptureMode("a", 1280, 720, 30, 30, false, "encoder", 2_000_000) + val hevc = base.copy(videoCodec = StreamVideoCodec.H265, minimumBitrate = 500000, maximumBitrate = 3000000) + assertEquals(hevc, StreamCameraModes.choose(listOf(base, hevc), hevc)) + val config = StreamCaptureConfig(base, StreamOrientation.LEFT, 4000000).withMode(hevc) + assertEquals(3000000, config.bitrate); assertEquals(StreamOrientation.LEFT, config.orientation) + } +}