fix:调整渲染任务调度和渲染间隔

This commit is contained in:
liyi 2025-06-18 14:53:43 +08:00
parent 6e7adbbc2f
commit c8a4e5d28e

View File

@ -49,7 +49,7 @@ class VideoDecoder(
companion object { companion object {
private const val TAG = "VideoDecoder" private const val TAG = "VideoDecoder"
private const val TIMEOUT_US = 10000L private const val TIMEOUT_US = 10000L
private const val INPUT_BUFFER_QUEUE_CAPACITY = 50 // 输入缓冲区容量 private const val INPUT_BUFFER_QUEUE_CAPACITY = 100 // 增大输入缓冲区容量
} }
// region 成员变量定义 // region 成员变量定义
@ -64,19 +64,23 @@ class VideoDecoder(
private var running = true // 解码器运行状态 private var running = true // 解码器运行状态
private val frameSeqSet = Collections.newSetFromMap(ConcurrentHashMap<Int, Boolean>()) // 防止重复帧入队 private val frameSeqSet = Collections.newSetFromMap(ConcurrentHashMap<Int, Boolean>()) // 防止重复帧入队
// 解码输出缓冲区,容量为100帧 // 解码输出缓冲区,增大容量
private val outputFrameQueue = LinkedBlockingQueue<DecodedFrame>(50) private val outputFrameQueue = LinkedBlockingQueue<DecodedFrame>(100)
// 渲染线程控制 // 渲染线程控制
// 定时渲染调度器
private var scheduler = Executors.newSingleThreadScheduledExecutor() private var scheduler = Executors.newSingleThreadScheduledExecutor()
private var lastRenderTimeMs = 0L // 记录上次渲染时间
// 这些变量移到init块中因为它们依赖renderFps
private var renderIntervalMs: Long = 0
private val renderJitterMs = 2L // 允许的渲染时间抖动范围
// 主线程Handler用于安全切换onFrameRendered到主线程 // 主线程Handler用于安全切换onFrameRendered到主线程
private val mainHandler = Handler(Looper.getMainLooper()) private val mainHandler = Handler(Looper.getMainLooper())
// 渲染帧率fps可由外部控制默认30 // 渲染帧率fps可由外部控制默认30
@Volatile @Volatile
var renderFps: Int = 30 var renderFps: Int = 20
// 兜底记录最近一次I帧的frameSeqP/B帧依赖校验 // 兜底记录最近一次I帧的frameSeqP/B帧依赖校验
@Volatile @Volatile
@ -128,6 +132,9 @@ class VideoDecoder(
// region 初始化与解码器配置 // region 初始化与解码器配置
init { init {
// 初始化渲染相关参数
renderIntervalMs = (1000.0 / renderFps).toLong()
// 配置Surface尺寸 // 配置Surface尺寸
surfaceTexture.setDefaultBufferSize(width, height) surfaceTexture.setDefaultBufferSize(width, height)
// 选择MIME类型 // 选择MIME类型
@ -139,11 +146,19 @@ class VideoDecoder(
// 创建并配置MediaFormat // 创建并配置MediaFormat
val format = MediaFormat.createVideoFormat(mime, width, height) val format = MediaFormat.createVideoFormat(mime, width, height)
format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, width * height) format.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, width * height)
format.setInteger(MediaFormat.KEY_FRAME_RATE, renderFps) // 移除可能导致flush的配置
format.setInteger(MediaFormat.KEY_LOW_LATENCY, 1); // format.setInteger(MediaFormat.KEY_FRAME_RATE, renderFps)
format.setInteger(MediaFormat.KEY_PRIORITY, 0) // 最高优先级 // format.setInteger(MediaFormat.KEY_OPERATING_RATE, renderFps)
format.setInteger(MediaFormat.KEY_OPERATING_RATE, renderFps * 2) // 解码速率 format.setInteger(MediaFormat.KEY_LOW_LATENCY, 1)
format.setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0) // 禁用B帧 format.setInteger(MediaFormat.KEY_PRIORITY, 0)
format.setInteger(MediaFormat.KEY_MAX_B_FRAMES, 0)
// 高通解码器特定配置
format.setInteger("vendor.qti-ext-dec-low-latency.enable", 1)
format.setInteger("vendor.qti-ext-dec-picture-order.enable", 0)
format.setInteger("vendor.qti-ext-dec-timestamp-mode.value", 0) // 使用原始时间戳
format.setInteger("vendor.qti-ext-dec-drv-flush.disable", 1) // 禁用驱动层flush
// 创建解码器 // 创建解码器
val decoder = MediaCodec.createDecoderByType(mime) val decoder = MediaCodec.createDecoderByType(mime)
// 设置解码回调 // 设置解码回调
@ -210,16 +225,23 @@ class VideoDecoder(
decoder.start() decoder.start()
mediaCodec = decoder mediaCodec = decoder
// 启动定时渲染任务,实现完全线性调度 // 优化渲染任务调度
// 说明本方案通过ScheduledExecutorService定时驱动渲染每帧间隔严格等距不依赖阻塞或sleep
var hasNotifiedFlutter = false var hasNotifiedFlutter = false
var renderedFrameCount = 0 // 渲染帧计数器 var renderedFrameCount = 0
val renderTask = Runnable { val renderTask = Runnable {
try { try {
val now = System.currentTimeMillis()
// 控制渲染间隔,避免过快渲染
val timeSinceLastRender = now - lastRenderTimeMs
if (timeSinceLastRender < renderIntervalMs - renderJitterMs) {
return@Runnable
}
val frame = outputFrameQueue.poll() val frame = outputFrameQueue.poll()
if (frame != null) { if (frame != null) {
frame.codec.releaseOutputBuffer(frame.bufferIndex, true) frame.codec.releaseOutputBuffer(frame.bufferIndex, true)
latestRenderedTimestampMs = System.currentTimeMillis() lastRenderTimeMs = now
latestRenderedTimestampMs = now
renderedFrameCount++ renderedFrameCount++
if (!hasNotifiedFlutter) { if (!hasNotifiedFlutter) {
mainHandler.post { onFrameRendered() } mainHandler.post { onFrameRendered() }
@ -229,13 +251,13 @@ class VideoDecoder(
} else { } else {
Log.w(TAG, "[Render] 渲染空转无帧可渲染当前outputFrameQueue=${outputFrameQueue.size}") Log.w(TAG, "[Render] 渲染空转无帧可渲染当前outputFrameQueue=${outputFrameQueue.size}")
} }
// 若outputFrameQueue为空跳过本次渲染实现线性调度
} catch (e: Exception) { } catch (e: Exception) {
Log.e(TAG, "[RenderTask] Exception", e) Log.e(TAG, "[RenderTask] Exception", e)
} }
} }
// 固定20fps渲染50ms间隔
scheduler.scheduleAtFixedRate(renderTask, 0, 50, java.util.concurrent.TimeUnit.MILLISECONDS) // 使用更短的调度间隔,但在任务中控制实际渲染间隔
scheduler.scheduleAtFixedRate(renderTask, 0, renderIntervalMs/2, TimeUnit.MILLISECONDS)
} }
// endregion // endregion