fix:调整渲染任务调度和渲染间隔
This commit is contained in:
parent
6e7adbbc2f
commit
c8a4e5d28e
@ -49,7 +49,7 @@ class VideoDecoder(
|
||||
companion object {
|
||||
private const val TAG = "VideoDecoder"
|
||||
private const val TIMEOUT_US = 10000L
|
||||
private const val INPUT_BUFFER_QUEUE_CAPACITY = 50 // 输入缓冲区容量
|
||||
private const val INPUT_BUFFER_QUEUE_CAPACITY = 100 // 增大输入缓冲区容量
|
||||
}
|
||||
|
||||
// region 成员变量定义
|
||||
@ -64,19 +64,23 @@ class VideoDecoder(
|
||||
private var running = true // 解码器运行状态
|
||||
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 lastRenderTimeMs = 0L // 记录上次渲染时间
|
||||
|
||||
// 这些变量移到init块中,因为它们依赖renderFps
|
||||
private var renderIntervalMs: Long = 0
|
||||
private val renderJitterMs = 2L // 允许的渲染时间抖动范围
|
||||
|
||||
// 主线程Handler,用于安全切换onFrameRendered到主线程
|
||||
private val mainHandler = Handler(Looper.getMainLooper())
|
||||
|
||||
// 渲染帧率(fps),可由外部控制,默认30
|
||||
@Volatile
|
||||
var renderFps: Int = 30
|
||||
var renderFps: Int = 20
|
||||
|
||||
// 兜底:记录最近一次I帧的frameSeq,P/B帧依赖校验
|
||||
@Volatile
|
||||
@ -128,6 +132,9 @@ class VideoDecoder(
|
||||
|
||||
// region 初始化与解码器配置
|
||||
init {
|
||||
// 初始化渲染相关参数
|
||||
renderIntervalMs = (1000.0 / renderFps).toLong()
|
||||
|
||||
// 配置Surface尺寸
|
||||
surfaceTexture.setDefaultBufferSize(width, height)
|
||||
// 选择MIME类型
|
||||
@ -139,11 +146,19 @@ class VideoDecoder(
|
||||
// 创建并配置MediaFormat
|
||||
val format = MediaFormat.createVideoFormat(mime, width, height)
|
||||
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帧
|
||||
// 移除可能导致flush的配置
|
||||
// format.setInteger(MediaFormat.KEY_FRAME_RATE, renderFps)
|
||||
// format.setInteger(MediaFormat.KEY_OPERATING_RATE, renderFps)
|
||||
format.setInteger(MediaFormat.KEY_LOW_LATENCY, 1)
|
||||
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)
|
||||
// 设置解码回调
|
||||
@ -210,16 +225,23 @@ class VideoDecoder(
|
||||
decoder.start()
|
||||
mediaCodec = decoder
|
||||
|
||||
// 启动定时渲染任务,实现完全线性调度
|
||||
// 说明:本方案通过ScheduledExecutorService定时驱动渲染,每帧间隔严格等距,不依赖阻塞或sleep
|
||||
// 优化渲染任务调度
|
||||
var hasNotifiedFlutter = false
|
||||
var renderedFrameCount = 0 // 渲染帧计数器
|
||||
var renderedFrameCount = 0
|
||||
val renderTask = Runnable {
|
||||
try {
|
||||
val now = System.currentTimeMillis()
|
||||
// 控制渲染间隔,避免过快渲染
|
||||
val timeSinceLastRender = now - lastRenderTimeMs
|
||||
if (timeSinceLastRender < renderIntervalMs - renderJitterMs) {
|
||||
return@Runnable
|
||||
}
|
||||
|
||||
val frame = outputFrameQueue.poll()
|
||||
if (frame != null) {
|
||||
frame.codec.releaseOutputBuffer(frame.bufferIndex, true)
|
||||
latestRenderedTimestampMs = System.currentTimeMillis()
|
||||
lastRenderTimeMs = now
|
||||
latestRenderedTimestampMs = now
|
||||
renderedFrameCount++
|
||||
if (!hasNotifiedFlutter) {
|
||||
mainHandler.post { onFrameRendered() }
|
||||
@ -229,13 +251,13 @@ class VideoDecoder(
|
||||
} else {
|
||||
Log.w(TAG, "[Render] 渲染空转,无帧可渲染,当前outputFrameQueue=${outputFrameQueue.size}")
|
||||
}
|
||||
// 若outputFrameQueue为空,跳过本次渲染,实现线性调度
|
||||
} catch (e: Exception) {
|
||||
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
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user