如何解决Android平台H264解码器存在的解码延迟过高问题?
Android MediaCodec H264低延迟解码解决方案
Android 平台硬件 MediaCodec 默认会开启多帧缓冲逻辑来提升解码流畅度,针对你使用的无B帧、单帧可独立解码的实时H264流,可通过以下步骤完全解决缓冲延迟问题:
- 解码器初始化阶段开启低延迟模式
配置 MediaFormat 时添加低延迟参数,同时提前传入SPS、PPS参数集,避免解码器等待参数集导致首帧延迟:MediaFormat format = MediaFormat.createVideoFormat(MediaFormat.MIMETYPE_VIDEO_AVC, 视频宽度, 视频高度); // 传入编码端输出的SPS、PPS数据 format.setByteBuffer("csd-0", ByteBuffer.wrap(spsByteArray)); format.setByteBuffer("csd-1", ByteBuffer.wrap(ppsByteArray)); // 开启低延迟解码,Android 7.0及以上系统支持 if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { format.setInteger(MediaFormat.KEY_LOW_LATENCY, 1); } m_codec.configure(format, 输出Surface, null, 0); m_codec.start(); - 修正时间戳参数,避免全0值导致的解码逻辑异常
你当前代码所有帧的展示时间戳(pts)均传0,会导致解码器无法判断帧输出顺序,强制触发缓冲逻辑。即便不需要音视频同步,也需要设置递增的时间戳,1fps场景下可按每帧递增1000000微秒设置:// 定义全局变量记录当前时间戳 private long currentPts = 0; // 每送入一帧更新一次时间戳 currentPts += 1000000; m_codec.queueInputBuffer(inputIndex, 0, frame.length, currentPts, 0); - 替换不稳定的空NAL填充方案,改用帧推送后轮询输出逻辑
填充无意义NAL单元的方案容易触发解码器校验错误崩溃,改为单帧送入后多次短超时轮询输出缓冲区的方案,兼容性和稳定性更高,修改后的解码逻辑如下:byte[] frame = h264Data.toByteArray(); // 送入真实H264帧 int inputIndex = m_codec.dequeueInputBuffer(-1); if (inputIndex >= 0) { ByteBuffer buffer; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.LOLLIPOP){ buffer = m_codec.getInputBuffer(inputIndex); } else { ByteBuffer[] bbuf = m_codec.getInputBuffers(); buffer = bbuf[inputIndex]; } buffer.put(frame); // 使用递增的时间戳 currentPts += 1000000; m_codec.queueInputBuffer(inputIndex, 0, frame.length, currentPts, 0); } // 轮询取解码输出,最多轮询5次,每次超时1ms即可 MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); for (int i = 0; i < 5; i++) { int outputIndex = m_codec.dequeueOutputBuffer(info, 1000); if (outputIndex >= 0) { m_codec.releaseOutputBuffer(outputIndex, true); break; } else if (outputIndex == MediaCodec.INFO_TRY_AGAIN_LATER || outputIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { continue; } } - 额外优化建议
编码端每10~30秒插入一个I帧,携带完整SPS、PPS参数集,避免网络抖动或丢帧导致的花屏、解码器卡死问题。
内容的提问来源于stack exchange,提问作者Mohammad
相关产品推荐
相关产品推荐

