app-starlock/lib/talk/starChart/handle/other/h264_frame_handler.dart

106 lines
3.1 KiB
Dart

import 'dart:collection';
import 'dart:typed_data';
import 'package:star_lock/app_settings/app_settings.dart';
import '../../proto/talk_data_h264_frame.pb.dart';
class H264FrameHandler {
final LinkedHashMap<int, TalkDataH264Frame> _frameBuffer = LinkedHashMap();
final void Function(List<int> frameData) onCompleteFrame;
final LinkedHashMap<int, TalkDataH264Frame_FrameTypeE> _frameTypeIndex = LinkedHashMap();
H264FrameHandler({required this.onCompleteFrame});
void handleFrame(TalkDataH264Frame frame) {
// 存储帧
_frameBuffer[frame.frameSeq] = frame;
_frameTypeIndex[frame.frameSeq] = frame.frameType;
// 检查是否可以组装完整的 GOP (Group of Pictures)
_tryAssembleFrames(frame.frameSeq);
}
void _tryAssembleFrames(int currentSeq) {
final List<int> framesToProcess = [];
int? startFrameSeq;
// 从当前帧开始向前找到最近的 I 帧或 P 帧
for (int seq = currentSeq; seq >= 0; seq--) {
final frameType = _frameTypeIndex[seq];
if (frameType == null) continue;
if (frameType == TalkDataH264Frame_FrameTypeE.I) {
startFrameSeq = seq;
break;
} else if (frameType == TalkDataH264Frame_FrameTypeE.P) {
if (_frameBuffer.containsKey(_frameBuffer[seq]!.frameSeqI)) {
startFrameSeq = seq;
break;
} else {
_frameBuffer.remove(seq);
_frameTypeIndex.remove(seq);
}
}
}
if (startFrameSeq != null) {
for (int seq = startFrameSeq; _frameBuffer.containsKey(seq); seq++) {
framesToProcess.add(seq);
}
if (framesToProcess.isNotEmpty) {
_processFrames(framesToProcess);
}
} else {
_clearOldFrames(currentSeq);
}
}
void _processFrames(List<int> frameSeqs) {
// 按顺序组装帧数据
// final List<int> assembledData = [];
//
// for (var seq in frameSeqs) {
// final frame = _frameBuffer[seq]!;
// assembledData.addAll(frame.frameData);
//
// // 处理完后从缓冲区移除
// _frameBuffer.remove(seq);
// }
//
// // 回调完整的帧数据
// onCompleteFrame(assembledData);
// Calculate the total length of the assembled data
int totalLength = frameSeqs.fold(
0, (sum, seq) => sum + _frameBuffer[seq]!.frameData.length);
// Allocate a buffer for the assembled data
final assembledData = Uint8List(totalLength);
int offset = 0;
for (var seq in frameSeqs) {
final frame = _frameBuffer[seq]!;
assembledData.setRange(
offset, offset + frame.frameData.length, frame.frameData);
offset += frame.frameData.length;
// Remove the frame from the buffer after processing
_frameBuffer.remove(seq);
_frameTypeIndex.remove(seq);
}
// Callback with the complete frame data
onCompleteFrame(assembledData);
}
void clear() {
_frameBuffer.clear();
}
void _clearOldFrames(int currentSeq) {
// 清理比当前帧序列旧的帧
_frameBuffer.removeWhere((seq, frame) => seq < currentSeq - 200); // 调整阈值
_frameTypeIndex.removeWhere((seq, frameType) => seq < currentSeq - 200);
}
}