Browse Source

Assemble partial codec setup and test real out of band decoder configuration

master
evgeny 5 days ago
parent
commit
49ca49fa1e
  1. 6
      doc/service_lifecycle.md
  2. 11
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamCaptureEngine.kt
  3. 1
      tools/chatgui/tests/test_stream_view.cpp

6
doc/service_lifecycle.md

@ -104,6 +104,12 @@ Live media хранится в RS-кольце с общим индексом PT
destroy отсоединённого cursor не обращается к store. Frontend прекращает audio callback
и worker до освобождения своего DSP; borrowed handle/RS pointers между потоками не передаются.
ACK-история принадлежит ядру и обновляется только при первом найденном подтверждении
пакета. REINIT/close соединения не стирает уже подтверждённые за последнюю секунду байты.
Android publisher владеет отдельным 100ms таймером TX-снимков; close/detach отменяют
его в uasync до уничтожения instance. JNI копирует снимок под mutex без доступа к
живым очередям транспорта из Kotlin. Экран подписан на отдельный StateFlow статистики.
Статус транспорта UP подтверждает восстановление физического пути. READY сессии
группы означает согласованный JOIN/ACCEPT и завершённый обмен её таблицей; именно
его ждёт recovery. REINIT меняет эпохи обмена, сохраняя рабочие маршруты. Эпохи

11
tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamCaptureEngine.kt

@ -62,6 +62,7 @@ class StreamCaptureEngine(
private var originNs = 0L
private var csd = byteArrayOf()
private val partial = ByteArrayOutputStream()
private val partialConfig = ByteArrayOutputStream()
private var partialPts = 0L
private var partialKey = false
private var requireKey = true
@ -131,7 +132,7 @@ class StreamCaptureEngine(
preview.register(token, cameraPose)
LogManager.addLog("DEBUG", "video", "preview camera id=$id revision=$token camera=${mode.camera} " +
"sensor=${cameraPose.sensor} front=${cameraPose.front} broadcastRotation=$rotation")
csd = byteArrayOf(); partial.reset(); requireKey = true; lastKeyRequest = 0; waitingFirst = true
csd = byteArrayOf(); partial.reset(); partialConfig.reset(); requireKey = true; lastKeyRequest = 0; waitingFirst = true
confirming = mode.highSpeed; confirmStartNs = 0
reportNs = System.nanoTime(); reportFrames = encodedFrames; reportBytes = bytesSent
if (switchStartedNs == 0L) switchStartedNs = reportNs
@ -166,7 +167,11 @@ class StreamCaptureEngine(
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) {
csd = mode.videoCodec.mergeConfig(csd, bytes)
check(partialConfig.size() + bytes.size <= StreamVideoCodec.MAX_CONFIG)
partialConfig.write(bytes)
if (info.flags and MediaCodec.BUFFER_FLAG_PARTIAL_FRAME == 0) {
csd = mode.videoCodec.mergeConfig(csd, partialConfig.toByteArray()); partialConfig.reset()
}
} else encoded(bytes, info, config, rotation, token)
}
if (info.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0) problem = "unexpected encoder EOS"
@ -352,7 +357,7 @@ class StreamCaptureEngine(
val done = releaseDone ?: return
try { encoder?.stop() } catch (e: Exception) { LogManager.addLog("WARN", "video", "encoder stop id=$id: ${e.message}") }
try { encoder?.release() } catch (e: Exception) { LogManager.addLog("WARN", "video", "encoder release id=$id: ${e.message}") }
encoder = null; input?.release(); input = null; partial.reset(); csd = byteArrayOf(); releaseDone = null
encoder = null; input?.release(); input = null; partial.reset(); partialConfig.reset(); csd = byteArrayOf(); releaseDone = null
LogManager.addLog("DEBUG", "video", "video resources released id=$id closed=$closed revision=$generation")
done(closed)
}

1
tools/chatgui/tests/test_stream_view.cpp

@ -265,6 +265,7 @@ private slots:
AVCodecContext* context = avcodec_alloc_context3(encoder); QVERIFY(context);
context->width = 160; context->height = 90; context->pix_fmt = AV_PIX_FMT_YUV420P; context->bit_rate = 200000;
context->time_base = {1, 30}; context->framerate = {30, 1}; context->max_b_frames = 0; context->thread_count = 1; context->gop_size = 1;
context->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
AVDictionary* options = nullptr;
if (fixture.type == STREAM_MEDIA_H265) {
av_dict_set(&options, "preset", "ultrafast", 0); av_dict_set(&options, "tune", "zerolatency", 0);

Loading…
Cancel
Save