# Video Decode Plugin > 当前版本:0.0.1 > 最低 Flutter SDK 要求:>=3.3.0 > 最低 Dart SDK 要求:>=3.3.4 ## 安装 ```yaml dependencies: video_decode_plugin: ^0.0.1 # 使用最新版本 ``` ## 插件简介与环境要求 本插件为Flutter平台下的裸流H.264/H.265实时视频解码渲染插件,支持Android与iOS - Flutter SDK: >=3.3.0 - Dart SDK: >=3.3.4 - Android: minSdkVersion 21+ - iOS: 11.0+ ## 快速开始(单实例标准用法) ```dart import 'package:video_decode_plugin/video_decode_plugin.dart'; // 1. 创建解码器配置 final config = VideoDecoderConfig( width: 640, // 视频宽度 height: 480, // 视频高度 codecType: 'h264', // 编解码类型:h264或h265 ); // 2. 初始化解码器,获取纹理ID final textureId = await VideoDecodePlugin.initDecoder(config); // 3. 设置帧渲染回调(可选) // 第一帧被渲染时触发的回调 VideoDecodePlugin.setOnFrameRenderedListener((textureId) { // 新帧渲染时回调 setState(() {}); }); // 4. 渲染视频(Flutter端) AspectRatio( aspectRatio: 640/480, // 建议与视频源一致 child: Container( color: Colors.transparent, child: Texture( textureId: textureId!, filterQuality: FilterQuality.medium, ), ), ) // 5. 推送视频帧(SPS/PPS/I帧/P帧) await VideoDecodePlugin.sendFrame( frameData: sps, frameType: 0, timestamp: ..., frameSeq: ... ); await VideoDecodePlugin.sendFrame( frameData: pps, frameType: 0, timestamp: ..., frameSeq: ... ); await VideoDecodePlugin.sendFrame( frameData: iFrame, frameType: 0, timestamp: ..., frameSeq: ... ); await VideoDecodePlugin.sendFrame( frameData: pFrame, frameType: 1, timestamp: ..., frameSeq: ..., refIFrameSeq: ... ); // 6. 释放资源 await VideoDecodePlugin.releaseDecoder(); ``` ## 推荐推送流程(伪代码) ```dart // 发送SPS和PPS await VideoDecodePlugin.sendFrame(frameData: sps, frameType: 0, ...); await VideoDecodePlugin.sendFrame(frameData: pps, frameType: 0, ...); // 发送I帧 await VideoDecodePlugin.sendFrame(frameData: iFrame, frameType: 0, ...); // 发送P帧 await VideoDecodePlugin.sendFrame(frameData: pFrame, frameType: 1, refIFrameSeq: iFrameSeq, ...); ``` ## 必须做的前置操作 - **推送顺序**:务必保证每个I帧前都已推送最新SPS(NAL类型7)、PPS(NAL类型8),再推送I帧(NAL类型5),最后推送P帧(NAL类型1)。 - **依赖链完整性校验**:业务端需实现I帧序号管理,P帧推送前校验refIFrameSeq是否为已解码I帧,否则丢弃。 - **丢帧策略**:强烈建议业务端实现丢帧与依赖链管理,避免无效帧流入原生端。 - **异常自愈**:检测到解码失败/花屏/长时间无I帧时,建议主动reset解码器,等待下一个I帧恢复链路。 - **日志监控**:建议业务端和原生端均输出详细日志,便于端到端排查依赖链断裂、丢包、乱序等问题。 ## 重要注意事项 - **只推送标准NALU**:仅推送type=1的P帧、type=5的I帧、type=7/8的SPS/PPS进入解码器,SEI等异常NALU自动丢弃。 - **Flutter端布局建议**:建议用AspectRatio、FittedBox等包裹Texture,确保宽高比一致,避免白边。父容器背景色建议设为透明。 - **iOS端Texture机制说明**:Flutter Texture机制下无法直接控制原生UIView属性(contentMode等),如需更强原生控制力可考虑PlatformView方案。 - **Android/iOS平台差异**:iOS端VideoToolbox对NALU格式、推送顺序要求更严格,务必保证数据流规范。 ## 常见问题与排查建议 - **花屏/马赛克**:多因I帧依赖链断裂、SPS/PPS/I帧推送顺序错误、数据丢包、NALU内容异常导致。请重点排查推送顺序与依赖链。 - **白边/拉伸**:多因Flutter端布局宽高比不一致或父容器背景色非透明。建议用AspectRatio/FittedBox包裹Texture。 - **P帧丢弃**:如P帧依赖的I帧未解码,P帧会被自动丢弃,防止花屏。 - **iOS端解码失败**:请确保推送NALU类型、顺序、内容均规范,iOS端容错性低于Android。 - **Android帧率较低**:确保使用了硬解码、三层缓冲区被正常使用 ## iOS端实现架构简述 - iOS端基于VideoToolbox实现H264/H265硬件解码,输出CVPixelBuffer。 - 插件内部实现了解码输入缓冲区、输出缓冲区,解码与渲染完全解耦。 - 独立渲染线程定时从输出缓冲区取帧,刷新Flutter纹理,支持EMA自适应帧率平滑调整,提升流畅度与健壮性。 - P帧推送前会校验依赖的I帧是否已解码,若依赖链断裂则P帧直接丢弃,避免马赛克。 - 仅推送标准NALU(type=1的P帧、type=5的I帧、type=7/8的SPS/PPS)进入解码器,SEI等异常NALU自动丢弃。 - 由于Flutter Texture机制无法直接控制原生UIView属性,建议Flutter端容器背景色设为透明,布局自适应。 - 如需更强原生控制力,可考虑自定义PlatformView方案。 ## 版本历史 ### 0.0.1 - 2025.04 - ✨ 初始版本发布 - 🎯 基础功能实现: - H.264 解码支持 - 实时视频流解码 - 基础错误处理 ## H.264解码注意事项 ### 马赛克/花屏出现的根因 - **依赖链断裂**:P/B帧依赖的I帧未被解码成功,或I帧本身丢失/损坏,后续P/B帧全部解码失败,必然花屏。 - **SPS/PPS/I帧推送顺序错误**:未按SPS→PPS→I帧顺序推送,或I帧前未收到最新SPS/PPS,解码器无法正确解码I帧。 - **解码链断裂后未及时reset解码器**:解码器内部状态异常,后续即使收到新I帧也无法恢复,需reset解码器。