From 6e44ee8b48869624ef2668d0fdc0f3d1af336f3f Mon Sep 17 00:00:00 2001 From: liyi Date: Mon, 23 Jun 2025 15:30:08 +0800 Subject: [PATCH] =?UTF-8?q?fix:=E8=B0=83=E6=95=B4=E6=B8=B2=E6=9F=93?= =?UTF-8?q?=E7=BC=93=E5=86=B2=E5=8C=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../video_decode_plugin/VideoDecoder.kt | 64 ++++++++++++++++--- 1 file changed, 56 insertions(+), 8 deletions(-) diff --git a/android/src/main/kotlin/top/skychip/video_decode_plugin/VideoDecoder.kt b/android/src/main/kotlin/top/skychip/video_decode_plugin/VideoDecoder.kt index 3b5303d..c5365d9 100644 --- a/android/src/main/kotlin/top/skychip/video_decode_plugin/VideoDecoder.kt +++ b/android/src/main/kotlin/top/skychip/video_decode_plugin/VideoDecoder.kt @@ -80,7 +80,7 @@ class VideoDecoder( // 渲染帧率(fps),可由外部控制,默认30 @Volatile - var renderFps: Int = 25 + var renderFps: Int = 20 // 兜底:记录最近一次I帧的frameSeq,P/B帧依赖校验 @Volatile @@ -111,6 +111,10 @@ class VideoDecoder( private val reorderLock = ReentrantLock() // 线程安全 private val MAX_REORDER_BUFFER_SIZE = BUFFER_QUEUE_CAPACITY + // 低水位启动渲染标志 + @Volatile + private var renderStarted = false + // 输入帧结构体 private data class FrameData( val data: ByteArray, @@ -161,6 +165,39 @@ class VideoDecoder( // 创建解码器 val decoder = MediaCodec.createDecoderByType(mime) + + // ========== 输出所有支持的视频解码器及类型 ========== + try { + val codecList = if (android.os.Build.VERSION.SDK_INT >= 21) { + android.media.MediaCodecList(android.media.MediaCodecList.ALL_CODECS).codecInfos + } else { + arrayOf() + } + Log.i(TAG, "[CodecList] 支持的视频解码器如下:") + for (info in codecList) { + if (!info.isEncoder) { + val types = info.supportedTypes.joinToString(", ") + val name = info.name + val isHardware = if (android.os.Build.VERSION.SDK_INT >= 29) info.isHardwareAccelerated else !name.startsWith("OMX.google.") + val isSoftware = if (android.os.Build.VERSION.SDK_INT >= 29) info.isSoftwareOnly else name.startsWith("OMX.google.") + Log.i(TAG, "解码器名称: $name, 支持类型: [$types], 硬解码: $isHardware, 软解码: $isSoftware") + } + } + } catch (e: Exception) { + Log.w(TAG, "[CodecList] 获取解码器列表失败", e) + } + + // ========== 输出当前创建的解码器类型 ========== + try { + val codecInfo = decoder.codecInfo + val name = codecInfo.name + val isHardware = if (android.os.Build.VERSION.SDK_INT >= 29) codecInfo.isHardwareAccelerated else !name.startsWith("OMX.google.") + val isSoftware = if (android.os.Build.VERSION.SDK_INT >= 29) codecInfo.isSoftwareOnly else name.startsWith("OMX.google.") + Log.i(TAG, "[CurrentCodec] 当前解码器: $name, 硬解码: $isHardware, 软解码: $isSoftware") + } catch (e: Exception) { + Log.w(TAG, "[CurrentCodec] 获取当前解码器信息失败", e) + } + // 设置解码回调 decoder.setCallback(object : MediaCodec.Callback() { override fun onInputBufferAvailable(codec: MediaCodec, index: Int) { @@ -237,6 +274,17 @@ class VideoDecoder( return@Runnable } + // 低水位启动渲染逻辑 + if (!renderStarted) { + if (outputFrameQueue.size >= (BUFFER_QUEUE_CAPACITY * 0.15).toInt()) { + renderStarted = true + Log.i(TAG, "[Render] 渲染启动,outputFrameQueue已达低水位: ${outputFrameQueue.size}") + } else { + // 未达到低水位前不渲染 + return@Runnable + } + } + val frame = outputFrameQueue.poll() if (frame != null) { frame.codec.releaseOutputBuffer(frame.bufferIndex, true) @@ -247,10 +295,10 @@ class VideoDecoder( mainHandler.post { onFrameRendered() } hasNotifiedFlutter = true } - // Log.d(TAG, "[Render] 渲染: bufferIdx=${frame.bufferIndex}, pts=${frame.timestampUs}, " + -// "当前outputFrameQueue=${outputFrameQueue.size}") + Log.d(TAG, "[Render] 渲染: bufferIdx=${frame.bufferIndex}, pts=${frame.timestampUs}, " + + "当前outputFrameQueue=${outputFrameQueue.size}") } else { -// Log.w(TAG, "[Render] 渲染空转,无帧可渲染,当前outputFrameQueue=${outputFrameQueue.size}") + Log.w(TAG, "[Render] 渲染空转,无帧可渲染,当前outputFrameQueue=${outputFrameQueue.size}") } } catch (e: Exception) { Log.e(TAG, "[RenderTask] Exception", e) @@ -275,10 +323,10 @@ class VideoDecoder( refIFrameSeq: Int? ): Boolean { if (!running || mediaCodec == null) return false - if (!frameSeqSet.add(frameSeq)) { - Log.w(TAG, "[decodeFrame] 丢弃重复帧: type=$frameType, seq=$frameSeq, refI=$refIFrameSeq, ts=$timestamp") - 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) {