fix:v2版本优化

This commit is contained in:
liyi 2025-06-18 14:38:05 +08:00
parent 1015321979
commit 6e7adbbc2f

View File

@ -74,30 +74,28 @@ class VideoDecoder(
// 主线程Handler用于安全切换onFrameRendered到主线程
private val mainHandler = Handler(Looper.getMainLooper())
// 渲染帧率fps可由外部控制默认18
// 渲染帧率fps可由外部控制默认30
@Volatile
var renderFps: Int = 20
var renderFps: Int = 30
// 兜底记录最近一次I帧的frameSeqP/B帧依赖校验
@Volatile
private var lastIFrameSeq: Int? = null
// 解码输出帧时间戳队列(用于动态帧率统计和平滑)
private val decodeTimestampQueue = ArrayDeque<Long>(20) // 最多保存20帧时间戳
private val decodeTimestampLock = ReentrantLock() // 线程安全保护
// EMA平滑参数
@Volatile
private var smoothedFps: Double = 25.0 // 平滑后的渲染帧率
private val alpha = 0.2 // EMA平滑系数越大响应越快
private val minFps = 8 // 渲染帧率下限,防止过低
private val maxFps = 30 // 渲染帧率上限,防止过高
private val maxStep = 2.0 // 单次最大调整幅度,防止突变
// ====== 动态帧率统计与平滑相关内容已废弃,以下变量保留注释以便后续扩展 ======
// private val decodeTimestampQueue = ArrayDeque<Long>(20) // 最多保存20帧时间戳
// private val decodeTimestampLock = ReentrantLock() // 线程安全保护
// @Volatile
// private var smoothedFps: Double = 25.0 // 平滑后的渲染帧率
// private val alpha = 0.2 // EMA平滑系数越大响应越快
// private val minFps = 8 // 渲染帧率下限,防止过低
// private val maxFps = 30 // 渲染帧率上限,防止过高
// private val maxStep = 2.0 // 单次最大调整幅度,防止突变
// 1. 新增成员变量
@Volatile
private var latestRenderedTimestampMs: Long? = null
private val MAX_ALLOWED_DELAY_MS = 550 // 最大允许延迟,单位毫秒
private val MAX_ALLOWED_DELAY_MS = 650 // 最大允许延迟,单位毫秒
@Volatile
private var timestampBaseMs: Long? = null
@Volatile
@ -143,7 +141,9 @@ class VideoDecoder(
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, width * height)
format.setInteger(MediaFormat.KEY_FRAME_RATE, renderFps)
format.setInteger(MediaFormat.KEY_LOW_LATENCY, 1);
format.setInteger(MediaFormat.KEY_PRIORITY, 0) // 最高优先级
format.setInteger(MediaFormat.KEY_OPERATING_RATE, renderFps * 2) // 解码速率
format.setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0) // 禁用B帧
// 创建解码器
val decoder = MediaCodec.createDecoderByType(mime)
// 设置解码回调
@ -159,7 +159,7 @@ class VideoDecoder(
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")
Log.w(TAG, "[onInputBufferAvailable] 丢弃延迟帧: absFrameTs=$absTimestamp, now=$now, maxDelay=$MAX_ALLOWED_DELAY_MS, seq=${frame.frameSeq}")
frameSeqSet.remove(frame.frameSeq)
codec.queueInputBuffer(index, 0, 0, 0, 0)
return
@ -171,6 +171,7 @@ class VideoDecoder(
inputBuffer.put(frame.data)
val start = System.nanoTime()
val ptsUs = absTimestamp * 1000L // 6. 送入解码器用绝对时间戳
// Log.d(TAG, "[MediaCodec] 入解码: type=${frame.frameType}, seq=${frame.frameSeq}, pts=$ptsUs, bufferIdx=$index")
codec.queueInputBuffer(
index,
0,
@ -187,14 +188,7 @@ class VideoDecoder(
}
override fun onOutputBufferAvailable(codec: MediaCodec, index: Int, info: MediaCodec.BufferInfo) {
if (!running) return
// 记录解码输出时间戳
val now = SystemClock.elapsedRealtime()
decodeTimestampLock.withLock {
if (decodeTimestampQueue.size >= 20) {
decodeTimestampQueue.removeFirst()
}
decodeTimestampQueue.addLast(now)
}
// ====== 动态帧率统计相关代码已注释,如需帧率统计可恢复 ======
// 解码后帧入输出缓冲区,由渲染线程处理
val frame = DecodedFrame(codec, index, MediaCodec.BufferInfo().apply {
set(0, info.size, info.presentationTimeUs, info.flags)
@ -203,7 +197,9 @@ class VideoDecoder(
// 缓冲区满,丢弃最旧帧再插入
outputFrameQueue.poll()
outputFrameQueue.offer(frame)
Log.w(TAG, "[MediaCodec] outputFrameQueue溢出丢弃最旧帧当前队列=${outputFrameQueue.size}")
}
// Log.d(TAG, "[MediaCodec] 输出: bufferIdx=$index, pts=${info.presentationTimeUs}, 当前outputFrameQueue=${outputFrameQueue.size}")
}
override fun onError(codec: MediaCodec, e: MediaCodec.CodecException) {
Log.e(TAG, "MediaCodec error", e)
@ -229,6 +225,9 @@ class VideoDecoder(
mainHandler.post { onFrameRendered() }
hasNotifiedFlutter = true
}
Log.d(TAG, "[Render] 渲染: bufferIdx=${frame.bufferIndex}, pts=${frame.timestampUs}, 当前outputFrameQueue=${outputFrameQueue.size}")
} else {
Log.w(TAG, "[Render] 渲染空转无帧可渲染当前outputFrameQueue=${outputFrameQueue.size}")
}
// 若outputFrameQueue为空跳过本次渲染实现线性调度
} catch (e: Exception) {
@ -253,7 +252,10 @@ class VideoDecoder(
refIFrameSeq: Int?
): Boolean {
if (!running || mediaCodec == null) return false
if (!frameSeqSet.add(frameSeq)) return false // 防止重复帧
if (!frameSeqSet.add(frameSeq)) {
Log.w(TAG, "[decodeFrame] 丢弃重复帧: type=$frameType, seq=$frameSeq, refI=$refIFrameSeq, ts=$timestamp")
return false // 防止重复帧
}
// 2. 初始化起点
if (timestampBaseMs == null) {
synchronized(this) {
@ -270,7 +272,7 @@ class VideoDecoder(
// 3. decodeFrame延迟丢弃判断用系统时间
val now = System.currentTimeMillis()
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")
Log.w(TAG, "[decodeFrame] 丢弃延迟帧: type=$frameType, seq=$frameSeq, absTs=$absTimestamp, now=$now, maxDelay=$MAX_ALLOWED_DELAY_MS")
return false
}
// ===== 帧重排序缓冲区机制 =====
@ -278,36 +280,43 @@ class VideoDecoder(
if (frameType == 0) { // I帧
receivedIFrames.add(frameSeq)
lastIFrameSeq = frameSeq
// Log.d(TAG, "[reorder] I帧到达: seq=$frameSeq, 当前缓存P帧数=${reorderBuffer.size}")
// I帧直接入解码队列
inputFrameQueue.offer(FrameData(frameData, frameType, timestamp, frameSeq, refIFrameSeq), 50, TimeUnit.MILLISECONDS)
inputFrameQueue.offer(FrameData(frameData, frameType, timestamp, frameSeq, refIFrameSeq), 150, TimeUnit.MILLISECONDS)
// 检查缓冲区入队所有依赖于该I帧的P帧
val readyPFrames = reorderBuffer.values.filter { it.refIFrameSeq == frameSeq }
.sortedBy { it.frameSeq }
// Log.d(TAG, "[reorder] I帧释放P帧: 依赖seq=$frameSeq, 释放P帧数=${readyPFrames.size}")
for (pFrame in readyPFrames) {
inputFrameQueue.offer(pFrame, 50, TimeUnit.MILLISECONDS)
inputFrameQueue.offer(pFrame, 150, TimeUnit.MILLISECONDS)
reorderBuffer.remove(pFrame.frameSeq)
}
// 清理过期P帧如缓冲区过大
if (reorderBuffer.size > MAX_REORDER_BUFFER_SIZE) {
val toRemove = reorderBuffer.keys.sorted().take(reorderBuffer.size - MAX_REORDER_BUFFER_SIZE)
Log.w(TAG, "[reorder] 缓冲区溢出清理P帧: 清理数=${toRemove.size}")
toRemove.forEach { reorderBuffer.remove(it) }
}
// Log.d(TAG, "[decodeFrame] 入队I帧: seq=$frameSeq, ts=$timestamp, 当前inputFrameQueue=${inputFrameQueue.size}")
return true
} else { // P帧
val lastI = lastIFrameSeq
// 只有依赖的I帧已收到才允许入队否则暂存
if (refIFrameSeq != null && receivedIFrames.contains(refIFrameSeq)) {
inputFrameQueue.offer(FrameData(frameData, frameType, timestamp, frameSeq, refIFrameSeq), 50, TimeUnit.MILLISECONDS)
inputFrameQueue.offer(FrameData(frameData, frameType, timestamp, frameSeq, refIFrameSeq), 150, TimeUnit.MILLISECONDS)
// Log.d(TAG, "[decodeFrame] 入队P帧: seq=$frameSeq, refI=$refIFrameSeq, ts=$timestamp, 当前inputFrameQueue=${inputFrameQueue.size}")
return true
} else {
// 暂存到重排序缓冲区
reorderBuffer[frameSeq] = FrameData(frameData, frameType, timestamp, frameSeq, refIFrameSeq)
Log.d(TAG, "[reorder] P帧缓存: seq=$frameSeq, refI=$refIFrameSeq, 当前缓存=${reorderBuffer.size}")
// 控制缓冲区大小
if (reorderBuffer.size > MAX_REORDER_BUFFER_SIZE) {
val toRemove = reorderBuffer.keys.sorted().take(reorderBuffer.size - MAX_REORDER_BUFFER_SIZE)
Log.w(TAG, "[reorder] 缓冲区溢出清理P帧: 清理数=${toRemove.size}")
toRemove.forEach { reorderBuffer.remove(it) }
}
Log.w(TAG, "[decodeFrame] P-frame cached: frameSeq=$frameSeq, refIFrameSeq=$refIFrameSeq, waiting for I-frame.")
Log.w(TAG, "[decodeFrame] P帧暂存: seq=$frameSeq, refI=$refIFrameSeq, 等待I帧")
return false
}
}
@ -334,33 +343,25 @@ class VideoDecoder(
} catch (_: Exception) {}
}
/**
* 计算最近N帧的平均解码帧率fps
*/
private fun calculateDecodeFps(): Double {
decodeTimestampLock.withLock {
if (decodeTimestampQueue.size < 2) return renderFps.toDouble()
val first = decodeTimestampQueue.first()
val last = decodeTimestampQueue.last()
val frameCount = decodeTimestampQueue.size - 1
val durationMs = (last - first).coerceAtLeast(1L)
return frameCount * 1000.0 / durationMs
}
}
// private fun calculateDecodeFps(): Double {
// decodeTimestampLock.withLock {
// if (decodeTimestampQueue.size < 2) return renderFps.toDouble()
// val first = decodeTimestampQueue.first()
// val last = decodeTimestampQueue.last()
// val frameCount = decodeTimestampQueue.size - 1
// val durationMs = (last - first).coerceAtLeast(1L)
// return frameCount * 1000.0 / durationMs
// }
// }
/**
* EMA平滑更新渲染帧率
* @param measuredFps 当前测得的解码帧率
* @return 平滑后的渲染帧率取整
*/
private fun updateSmoothedFps(measuredFps: Double): Int {
// measuredFps边界保护
val safeFps = measuredFps.coerceIn(minFps.toDouble(), maxFps.toDouble())
val targetFps = alpha * safeFps + (1 - alpha) * smoothedFps
val delta = targetFps - smoothedFps
val step = delta.coerceIn(-maxStep, maxStep)
smoothedFps = (smoothedFps + step).coerceIn(minFps.toDouble(), maxFps.toDouble())
return smoothedFps.toInt()
}
// private fun updateSmoothedFps(measuredFps: Double): Int {
// // measuredFps边界保护
// val safeFps = measuredFps.coerceIn(minFps.toDouble(), maxFps.toDouble())
// val targetFps = alpha * safeFps + (1 - alpha) * smoothedFps
// val delta = targetFps - smoothedFps
// val step = delta.coerceIn(-maxStep, maxStep)
// smoothedFps = (smoothedFps + step).coerceIn(minFps.toDouble(), maxFps.toDouble())
// return smoothedFps.toInt()
// }
// endregion
}