Browse Source

Bound desktop decoder work and drain Android codec with monotonic EOS timestamps

master
evgeny 5 days ago
parent
commit
be7c3c5811
  1. 13
      tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamPlayerEngine.kt
  2. 10
      tools/chatgui/src/streamplayer_window.cpp

13
tools/chatgui-android/app/src/main/java/com/utun/chat/data/StreamPlayerEngine.kt

@ -62,9 +62,10 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv
var generation = 0L
var decoded = 0L
var discarded = 0L
var decodedThrough = -1L
var lastSubmittedPts = -1L
var pendingOutput = -1
var pendingPts = 0L
var pendingEos = false
var eosQueued = false
var decoderEnded = false
var endUntil = 0L
@ -87,7 +88,7 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv
fun resetVideo() {
try { decoder?.stop(); decoder?.release() }
catch (e: Exception) { LogManager.addLog("WARN", "video", "decoder reset id=$id: ${e.message}") }
decoder = null; videos.clear(); submitted.clear(); pendingOutput = -1; decodedThrough = -1
decoder = null; videos.clear(); submitted.clear(); pendingOutput = -1; lastSubmittedPts = -1; pendingEos = false
waitingKey = true; eosQueued = false; decoderEnded = false
mutableStatus.value = R.string.stream_waiting_key
}
@ -237,14 +238,14 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv
val input = decoder!!.getInputBuffer(index) ?: error("Missing decoder input")
check(frame.data.size <= input.capacity()); input.clear(); input.put(frame.data)
decoder!!.queueInputBuffer(index, 0, frame.data.size, frame.pts, 0)
submitted.addLast(frame.pts); videos.removeFirst(); decoded++
submitted.addLast(frame.pts); lastSubmittedPts = frame.pts; videos.removeFirst(); decoded++
}
}
val codec = decoder
if (codec != null) {
if (ended && videos.isEmpty() && !eosQueued) {
val index = codec.dequeueInputBuffer(0)
if (index >= 0) { codec.queueInputBuffer(index, 0, 0, decodedThrough.coerceAtLeast(0) + 1,
if (index >= 0) { codec.queueInputBuffer(index, 0, 0, lastSubmittedPts.coerceAtLeast(0),
MediaCodec.BUFFER_FLAG_END_OF_STREAM); eosQueued = true }
}
repeat(8) {
@ -254,12 +255,14 @@ class StreamPlayerEngine(private val group: Long, private val source: Long, priv
if (info.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0 && info.size == 0) {
codec.releaseOutputBuffer(index, false); decoderEnded = true; return@repeat
}
pendingOutput = index; pendingPts = info.presentationTimeUs; decodedThrough = pendingPts
pendingOutput = index; pendingPts = info.presentationTimeUs
pendingEos = info.flags and MediaCodec.BUFFER_FLAG_END_OF_STREAM != 0
while (submitted.isNotEmpty() && submitted.first <= pendingPts) submitted.removeFirst()
}
if (pendingPts > position) return@repeat
val render = pendingPts >= position - 100000
codec.releaseOutputBuffer(pendingOutput, render); pendingOutput = -1
if (pendingEos) { decoderEnded = true; pendingEos = false }
if (!render) discarded++ else mutableStatus.value = R.string.stream_live
}
}

10
tools/chatgui/src/streamplayer_window.cpp

@ -309,6 +309,11 @@ void StreamPlayerWindow::decode() {
int received;
while ((received = avcodec_receive_frame(decoder, frame)) == 0) {
decoded++;
if (frame->width <= 0 || frame->width > 4096 || frame->height <= 0 || frame->height > 4096) {
DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop H264 dimensions invalid id=%llu size=%dx%d",
(unsigned long long)p.id, frame->width, frame->height);
fail(text("Invalid stream video dimensions")); p.running = false; break;
}
int64_t pts = frame->best_effort_timestamp == AV_NOPTS_VALUE ? (int64_t)record.pts : frame->best_effort_timestamp;
{ std::lock_guard<std::mutex> guard(p.lock); if (pts < p.clock(nowUs()) - 100000) { discarded++; continue; } }
converter = sws_getCachedContext(converter, frame->width, frame->height, (AVPixelFormat)frame->format,
@ -322,6 +327,11 @@ void StreamPlayerWindow::decode() {
}
if (record.format.rotation) image = image.transformed(QTransform().rotate(record.format.rotation));
std::lock_guard<std::mutex> guard(p.lock);
if (p.videos.size() >= 4) {
DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "desktop video preparation exceeded id=%llu frames=%zu",
(unsigned long long)p.id, p.videos.size());
fail(text("Stream video decoder failed")); p.running = false; break;
}
p.videoBytes += (size_t)image.sizeInBytes(); p.videos.push_back({std::move(image), pts});
}
if (received != AVERROR(EAGAIN) && received != AVERROR_EOF && p.running) {

Loading…
Cancel
Save