feat:增加帧超时丢弃策略;调整缓冲区大小

This commit is contained in:
liyi 2025-05-06 11:43:14 +08:00
parent fa01db3fa3
commit 5ea20835ec

View File

@ -48,7 +48,7 @@ class VideoDecoder(
companion object {
private const val TAG = "VideoDecoder"
private const val TIMEOUT_US = 10000L
private const val INPUT_BUFFER_QUEUE_CAPACITY = 250 // 输入缓冲区容量
private const val INPUT_BUFFER_QUEUE_CAPACITY = 30 // 输入缓冲区容量
}
// region 成员变量定义
@ -64,7 +64,7 @@ class VideoDecoder(
private val frameSeqSet = Collections.newSetFromMap(ConcurrentHashMap<Int, Boolean>()) // 防止重复帧入队
// 解码输出缓冲区容量为100帧
private val outputFrameQueue = LinkedBlockingQueue<DecodedFrame>(100)
private val outputFrameQueue = LinkedBlockingQueue<DecodedFrame>(30)
// 渲染线程控制
@Volatile private var renderThreadRunning = true
@ -90,6 +90,12 @@ class VideoDecoder(
private val maxFps = 30 // 渲染帧率上限,防止过高
private val maxStep = 2.0 // 单次最大调整幅度,防止突变
// 1. 新增成员变量
@Volatile private var latestRenderedTimestampMs: Long? = null
private val MAX_ALLOWED_DELAY_MS = 60 // 最大允许延迟,单位毫秒
@Volatile private var timestampBaseMs: Long? = null
@Volatile private var firstFrameRelativeTimestamp: Long? = null
// 输入帧结构体
private data class FrameData(
val data: ByteArray,
@ -131,14 +137,24 @@ class VideoDecoder(
// 从输入队列取出一帧数据
val frame = inputFrameQueue.poll()
if (frame != null) {
// 5. 取绝对时间戳
val base = timestampBaseMs ?: 0L
val firstRel = firstFrameRelativeTimestamp ?: 0L
val absTimestamp = base + (frame.timestamp - firstRel)
val now = System.currentTimeMillis()
if (absTimestamp < now - MAX_ALLOWED_DELAY_MS) {
Log.w(TAG, "[onInputBufferAvailable] Drop frame due to delay: absFrameTs=$absTimestamp, now=$now, maxDelay=$MAX_ALLOWED_DELAY_MS")
frameSeqSet.remove(frame.frameSeq)
codec.queueInputBuffer(index, 0, 0, 0, 0)
return
}
frameSeqSet.remove(frame.frameSeq)
val inputBuffer = codec.getInputBuffer(index)
if (inputBuffer != null) {
inputBuffer.clear()
inputBuffer.put(frame.data)
val start = System.nanoTime()
val ptsUs = frame.timestamp * 1000L
// 入队到解码器
val ptsUs = absTimestamp * 1000L // 6. 送入解码器用绝对时间戳
codec.queueInputBuffer(
index,
0,
@ -196,6 +212,8 @@ class VideoDecoder(
// 阻塞式等待新帧,避免空转
val frame = outputFrameQueue.take()
frame.codec.releaseOutputBuffer(frame.bufferIndex, true)
// 7. 渲染线程用系统时间推进
latestRenderedTimestampMs = System.currentTimeMillis()
renderedFrameCount++
// 只在首次渲染时回调Flutter
if (!hasNotifiedFlutter) {
@ -247,6 +265,27 @@ class VideoDecoder(
): Boolean {
if (!running || mediaCodec == null) return false
if (!frameSeqSet.add(frameSeq)) return false // 防止重复帧
// 2. 初始化起点
if (timestampBaseMs == null) {
synchronized(this) {
if (timestampBaseMs == null) {
timestampBaseMs = System.currentTimeMillis()
firstFrameRelativeTimestamp = timestamp
Log.i(TAG, "[timestampBase] Set timestampBaseMs=$timestampBaseMs, firstFrameRelativeTimestamp=$firstFrameRelativeTimestamp")
}
}
}
val base = timestampBaseMs ?: 0L
val firstRel = firstFrameRelativeTimestamp ?: 0L
val absTimestamp = base + (timestamp - firstRel)
// 3. decodeFrame延迟丢弃判断用系统时间
val now = System.currentTimeMillis()
val diff = now - absTimestamp
// Log.d(TAG, "[decodeFrame] absTimestamp=$absTimestamp, now=$now, now-absTimestamp=$diff, maxDelay=$MAX_ALLOWED_DELAY_MS")
if (absTimestamp < now - MAX_ALLOWED_DELAY_MS) {
Log.w(TAG, "[decodeFrame] Drop frame due to delay: absFrameTs=$absTimestamp, now=$now, maxDelay=$MAX_ALLOWED_DELAY_MS")
return false
}
var allow = false
if (frameType == 0) { // I帧
lastIFrameSeq = frameSeq
@ -263,6 +302,7 @@ class VideoDecoder(
return false
}
}
// 4. 入队时FrameData仍用原始相对时间戳
return inputFrameQueue.offer(FrameData(frameData, frameType, timestamp, frameSeq, refIFrameSeq), 50, TimeUnit.MILLISECONDS)
}