142 lines
4.1 KiB
Dart
142 lines
4.1 KiB
Dart
import 'dart:typed_data';
|
||
|
||
import 'package:flutter_easyloading/flutter_easyloading.dart';
|
||
import 'package:get/get.dart';
|
||
import 'package:star_lock/talk/startChart/entity/scp_message.dart';
|
||
import 'package:star_lock/talk/startChart/handle/scp_message_base_handle.dart';
|
||
import 'package:star_lock/talk/startChart/handle/scp_message_handle.dart';
|
||
import 'package:star_lock/talk/startChart/proto/gateway_reset.pb.dart';
|
||
import 'package:star_lock/talk/startChart/proto/generic.pb.dart';
|
||
import 'package:star_lock/talk/startChart/proto/talk_data.pb.dart';
|
||
import 'package:star_lock/talk/startChart/proto/talk_data.pbserver.dart';
|
||
|
||
import '../../start_chart_manage.dart';
|
||
|
||
class UdpTalkDataHandler extends ScpMessageBaseHandle
|
||
implements ScpMessageHandler {
|
||
@override
|
||
void handleReq(ScpMessage scpMessage) {}
|
||
|
||
@override
|
||
void handleResp(ScpMessage scpMessage) {}
|
||
|
||
@override
|
||
void handleInvalidReq(ScpMessage scpMessage) {}
|
||
|
||
@override
|
||
void handleRealTimeData(ScpMessage scpMessage) {
|
||
print('收到音视频数据:$scpMessage');
|
||
if (scpMessage.Payload != null) {
|
||
final TalkData talkData = scpMessage.Payload;
|
||
// 处理音视频数据
|
||
_handleTalkData(talkData: talkData);
|
||
// 收到数据后调用更新,防止定时器超时
|
||
talkDataOverTimeTimerManager.receiveMessage();
|
||
}
|
||
}
|
||
|
||
void _handleTalkData({required TalkData talkData}) {
|
||
if (talkData == null) return;
|
||
final contentType = talkData.contentType;
|
||
switch (contentType) {
|
||
case TalkData_ContentTypeE.H264:
|
||
_handleVideoH264(talkData);
|
||
break;
|
||
case TalkData_ContentTypeE.Image:
|
||
_handleVideoImage(talkData);
|
||
break;
|
||
case TalkData_ContentTypeE.G711:
|
||
_handleVideoG711(talkData);
|
||
break;
|
||
default:
|
||
print('❌未知的TalkData--->contentType类型');
|
||
break;
|
||
}
|
||
}
|
||
|
||
void _handleVideoH264(TalkData talkData) {
|
||
final List<int> content = talkData.content;
|
||
// 解析 H.264 NALU
|
||
_parseH264Nalus(content);
|
||
}
|
||
|
||
void _handleVideoImage(TalkData talkData) {}
|
||
|
||
void _handleVideoG711(TalkData talkData) {}
|
||
|
||
// 解析 H.264 NALU
|
||
void _parseH264Nalus(List<int> h264Stream) {
|
||
print('开始解析 H.264 NALU...');
|
||
|
||
int index = 0;
|
||
while (index < h264Stream.length) {
|
||
// 查找下一个 NALU 的起始码
|
||
int nextStartCodeIndex = findNextStartCode(h264Stream, index);
|
||
|
||
if (nextStartCodeIndex == -1) {
|
||
// 如果没有找到更多的起始码,结束解析
|
||
break;
|
||
}
|
||
|
||
// 提取当前 NALU
|
||
Uint8List naluData =
|
||
Uint8List.fromList(h264Stream.sublist(index, nextStartCodeIndex));
|
||
|
||
// 解析 NALU 头部
|
||
int naluType = naluData[0] & 0x1F; // NALU 类型位于第一个字节的低 5 位
|
||
print('找到 NALU,类型: $naluType,长度: ${naluData.length}');
|
||
|
||
// 根据 NALU 类型进行处理
|
||
handleNalu(naluType, naluData);
|
||
|
||
// 更新索引到下一个 NALU 的起始位置
|
||
index = nextStartCodeIndex;
|
||
}
|
||
}
|
||
|
||
// 查找下一个 NALU 的起始码
|
||
int findNextStartCode(List<int> data, int startIndex) {
|
||
for (int i = startIndex; i < data.length - 3; i++) {
|
||
// 检查 3 字节起始码
|
||
if (data[i] == 0x00 && data[i + 1] == 0x00 && data[i + 2] == 0x01) {
|
||
return i;
|
||
}
|
||
|
||
// 检查 4 字节起始码
|
||
if (i < data.length - 4 &&
|
||
data[i] == 0x00 &&
|
||
data[i + 1] == 0x00 &&
|
||
data[i + 2] == 0x00 &&
|
||
data[i + 3] == 0x01) {
|
||
return i;
|
||
}
|
||
}
|
||
|
||
// 如果没有找到更多的起始码,返回 -1
|
||
return -1;
|
||
}
|
||
|
||
// 处理 NALU
|
||
void handleNalu(int naluType, Uint8List naluData) {
|
||
switch (naluType) {
|
||
case 5:
|
||
print('IDR 帧 (关键帧)');
|
||
break;
|
||
case 1:
|
||
print('非 IDR 帧 (P 帧)');
|
||
break;
|
||
case 7:
|
||
print('SPS (序列参数集)');
|
||
break;
|
||
case 8:
|
||
print('PPS (图像参数集)');
|
||
break;
|
||
default:
|
||
print('其他 NALU 类型: $naluType');
|
||
}
|
||
|
||
// 你可以在这里根据 NALU 类型进行进一步处理
|
||
// 例如,将 SPS 和 PPS 传递给解码器,或将视频帧渲染到屏幕上
|
||
}
|
||
}
|