106 lines
3.1 KiB
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);
|
|
}
|
|
}
|