fix:文档更新

This commit is contained in:
liyi 2025-05-07 15:20:54 +08:00
parent dedf151273
commit 73afceeedc

260
README.md
View File

@ -4,10 +4,6 @@
> 最低 Flutter SDK 要求:>=3.3.0
> 最低 Dart SDK 要求:>=3.3.4
## 说明
- 目前只支持Android端解码
## 安装
```yaml
@ -15,206 +11,69 @@ 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 (Android 5.0)
- targetSdkVersion: 最新版本
- iOS:
- 最低版本: 11.0
- 开发环境: Xcode 最新版本
- Android: minSdkVersion 21+
- iOS: 11.0+
## 快速开始
### 在星锁项目中调试
1. 需切换到`develop_liyi`分支
2. 将本仓库代码拉取到本地后,在项目中增加本地的插件依赖
```dart
video_decode_plugin:
path: ../video_decode_plugin
```
3. `appRouters.dart`找到打开路由配置文件,在文件最下方切换配置路由地址
```dart
// GetPage<dynamic>(name: Routers.h264WebView, page: () => TalkViewNativeDecodePage()), // 插件播放页面
GetPage<dynamic>(name: Routers.h264WebView, page: () => H264WebView()), // webview播放页面
```
4. 使用插件调试则打开上一个注释同时注释掉weview的播放页面
### 初始化解码器
## 快速开始(单实例标准用法)
```dart
import 'package:video_decode_plugin/video_decode_plugin.dart';
// 创建解码器配置
// 1. 创建解码器配置
final config = VideoDecoderConfig(
width: 640, // 视频宽度
height: 480, // 视频高度
codecType: CodecType.h264, // 编解码类型h264或h265
frameRate: 30, // 目标帧率(可选)
isDebug: true, // 是否启用详细日志
codecType: 'h264', // 编解码类型h264或h265
);
// 初始化解码器获取纹理ID
// 2. 初始化解码器获取纹理ID
final textureId = await VideoDecodePlugin.initDecoder(config);
// 设置帧回调
VideoDecodePlugin.setFrameCallback((textureId) {
// 当新帧可用时被调用
setState(() {
// 更新UI
});
// 3. 设置帧渲染回调(可选)
// 第一帧被渲染时触发的回调
VideoDecodePlugin.setOnFrameRenderedListener((textureId) {
// 新帧渲染时回调
setState(() {});
});
```
### 渲染视频
```dart
// 使用Flutter的Texture组件显示视频
Texture(
textureId: textureId,
filterQuality: FilterQuality.low,
// 4. 渲染视频Flutter端
AspectRatio(
aspectRatio: 640/480, // 建议与视频源一致
child: Container(
color: Colors.transparent,
child: Texture(
textureId: textureId!,
filterQuality: FilterQuality.medium,
),
),
)
```
### 解码视频帧
```dart
// 解码I帧
await VideoDecodePlugin.decodeFrame(
frameData, // Uint8List类型的H.264/H.265帧数据
FrameType.iFrame
// 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: ...
);
// 解码P帧
await VideoDecodePlugin.decodeFrame(
frameData, // Uint8List类型的H.264/H.265帧数据
FrameType.pFrame
);
```
### 获取解码统计信息
```dart
final stats = await VideoDecodePlugin.getDecoderStats(textureId);
print('已渲染帧数: ${stats['renderedFrames']}');
print('丢弃帧数: ${stats['droppedFrames']}');
```
### 释放资源
```dart
// 6. 释放资源
await VideoDecodePlugin.releaseDecoder();
```
## 高级用法
## 推荐推送流程(伪代码)
### 多实例支持
插件支持同时创建和管理多个解码器实例:
```dart
// 创建第一个解码器
final textureId1 = await VideoDecodePlugin.createDecoder(config1);
// 创建第二个解码器
final textureId2 = await VideoDecodePlugin.createDecoder(config2);
// 为特定纹理ID设置回调
VideoDecodePlugin.setFrameCallbackForTexture(textureId1, (id) {
// 处理第一个解码器的帧
});
// 为特定纹理ID解码帧
await VideoDecodePlugin.decodeFrameForTexture(textureId2, frameData, frameType);
// 释放特定解码器
await VideoDecodePlugin.releaseDecoderForTexture(textureId1);
```
### 优化I帧和SPS/PPS处理
对于H.264视频流,建议按照以下顺序处理帧:
1. 首先发送SPS序列参数集NAL类型7
2. 其次发送PPS图像参数集NAL类型8
3. 然后发送IDR帧即I帧NAL类型5
4. 最后发送P帧NAL类型1
```dart
// 发送SPS和PPS数据
await VideoDecodePlugin.decodeFrame(spsData, FrameType.iFrame);
await VideoDecodePlugin.decodeFrame(ppsData, FrameType.iFrame);
// 发送IDR帧
await VideoDecodePlugin.decodeFrame(idrData, FrameType.iFrame);
// 发送P帧
await VideoDecodePlugin.decodeFrame(pFrameData, FrameType.pFrame);
```
## 完整示例
请参考示例应用,了解如何:
- 从文件或网络流加载H.264视频
- 正确解析和处理NAL单元
- 高效地解码和渲染视频帧
- 监控解码性能并进行故障排除
## 版本历史
### 0.0.1 - 2025.04
- ✨ 初始版本发布
- 🎯 基础功能实现:
- H.264/H.265 解码支持
- 实时视频流解码
- 基础错误处理
## 插件架构与职责
本插件为Flutter平台下的高性能、可扩展、易调试的视频解码渲染插件专注于Android端H.264/H.265实时流解码。
- **Flutter端职责**
- 负责NALU分割、SPS/PPS/I帧依赖链管理、滑动窗口丢帧、业务层帧流控制。
- 依赖链完整性校验P帧仅在依赖I帧已解码时才推送。
- 通过MethodChannel将帧数据、类型、序号等元数据传递到原生端。
- **Android端职责**
- 极简高效解码与渲染,主线程安全回调。
- 兜底依赖链校验,解码器生命周期管理,异常自愈。
## 文件结构与说明
### Dart端lib/
- **video_decode_plugin.dart**:插件主入口,负责解码器初始化、帧推送、回调注册、依赖链管理、与原生通信等。
- **frame_dependency_manager.dart**SPS/PPS/I帧依赖链滑动窗口管理支持I帧序号窗口、依赖校验、SPS/PPS缓存。
- **nalu_utils.dart**NALU分割与类型识别工具支持H.264/H.265帧的NALU单元分离、类型提取。
- **video_decode_plugin_platform_interface.dart**插件平台接口定义支持多平台扩展默认实现为MethodChannel。
- **video_decode_plugin_method_channel.dart**插件MethodChannel实现负责与原生端通信。
### Android端android/src/main/kotlin/top/skychip/video_decode_plugin/
- **VideoDecodePlugin.kt**插件原生入口注册MethodChannel管理解码器生命周期处理Flutter端方法调用。
- **VideoDecoder.kt**解码器核心实现负责MediaCodec解码、输入/输出队列、渲染线程、依赖链兜底校验、主线程回调、资源释放。
- **VideoDecoderConfig.kt**:解码器配置参数定义,支持分辨率、编解码类型、帧率、调试模式等。
## H.264解码注意事项
### 1. 马赛克/花屏出现的根因
- **依赖链断裂**P/B帧依赖的I帧未被解码成功或I帧本身丢失/损坏后续P/B帧全部解码失败必然花屏。
- **SPS/PPS/I帧推送顺序错误**未按SPS→PPS→I帧顺序推送或I帧前未收到最新SPS/PPS解码器无法正确解码I帧。
- **解码链断裂后未及时reset解码器**解码器内部状态异常后续即使收到新I帧也无法恢复需reset解码器。
### 2. 外部调用者(业务方)必须做好的前置操作
- **推送顺序**务必保证每个I帧前都已推送最新SPSNAL类型7、PPSNAL类型8再推送I帧NAL类型5最后推送P/B帧。
- **依赖链完整性校验**业务端需实现滑动窗口I帧序号管理P帧推送前校验refIFrameSeq是否在窗口内否则丢弃。
- **丢帧策略**:强烈建议业务端实现丢帧与依赖链管理,避免无效帧流入原生端。
- **异常自愈**:检测到解码失败/花屏/长时间无I帧时建议主动reset解码器等待下一个I帧恢复链路。
- **日志监控**:建议业务端和原生端均输出详细日志,便于端到端排查依赖链断裂、丢包、乱序等问题。
### 3. 推荐推送流程(伪代码)
```dart
// 发送SPS和PPS
await VideoDecodePlugin.sendFrame(frameData: sps, frameType: 0, ...);
@ -225,15 +84,54 @@ await VideoDecodePlugin.sendFrame(frameData: iFrame, frameType: 0, ...);
await VideoDecodePlugin.sendFrame(frameData: pFrame, frameType: 1, refIFrameSeq: iFrameSeq, ...);
```
## iOS端视频解码与渲染实现说明
## 必须做的前置操作
- **推送顺序**务必保证每个I帧前都已推送最新SPSNAL类型7、PPSNAL类型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帧直接丢弃避免马赛克。
- 仅推送标准NALUtype=1的P帧、type=5的I帧、type=7/8的SPS/PPS进入解码器SEI等异常NALU自动丢弃。
- Flutter端建议用AspectRatio、FittedBox等包裹Texture确保宽高比一致避免白边。
- 由于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解码器。