85 lines
2.4 KiB
Dart
85 lines
2.4 KiB
Dart
import 'package:star_lock/app_settings/app_settings.dart';
|
|
import '../../proto/talk_data_h264_frame.pb.dart';
|
|
|
|
class H264FrameHandler {
|
|
final Map<int, TalkDataH264Frame> _frameBuffer = {};
|
|
final void Function(List<int> frameData) onCompleteFrame;
|
|
int _lastProcessedSeq = -1;
|
|
|
|
H264FrameHandler({required this.onCompleteFrame});
|
|
|
|
void handleFrame(TalkDataH264Frame frame) {
|
|
// 存储帧
|
|
_frameBuffer[frame.frameSeq] = frame;
|
|
|
|
// 检查是否可以组装完整的 GOP (Group of Pictures)
|
|
_tryAssembleFrames(frame.frameSeq);
|
|
}
|
|
|
|
void _tryAssembleFrames(int currentSeq) {
|
|
// 找到连续的帧序列
|
|
final List<int> sortedSeqs = _frameBuffer.keys.toList()..sort();
|
|
final List<int> framesToProcess = [];
|
|
|
|
// 从当前帧开始向前找到最近的 I 帧或 P 帧
|
|
int? startFrameSeq;
|
|
for (var seq in sortedSeqs.reversed) {
|
|
final frame = _frameBuffer[seq];
|
|
if (frame?.frameType == TalkDataH264Frame_FrameTypeE.I) {
|
|
startFrameSeq = seq;
|
|
break;
|
|
} else if (frame?.frameType == TalkDataH264Frame_FrameTypeE.P) {
|
|
// 检查 P 帧是否有对应的 I 帧
|
|
if (_frameBuffer.containsKey(frame?.frameSeqI)) {
|
|
startFrameSeq = seq;
|
|
break;
|
|
} else {
|
|
// 丢弃没有对应 I 帧的 P 帧
|
|
_frameBuffer.remove(seq);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (startFrameSeq != null) {
|
|
// 收集从 I 帧或 P 帧开始的连续帧
|
|
int expectedSeq = startFrameSeq;
|
|
for (var seq in sortedSeqs.where((s) => s >= startFrameSeq!)) {
|
|
if (seq != expectedSeq) break;
|
|
framesToProcess.add(seq);
|
|
expectedSeq++;
|
|
}
|
|
|
|
if (framesToProcess.isNotEmpty) {
|
|
_processFrames(framesToProcess);
|
|
}
|
|
} else {
|
|
_clearOldFrames(currentSeq);
|
|
}
|
|
}
|
|
|
|
void _clearOldFrames(int currentSeq) {
|
|
// 清理比当前帧序列旧的帧
|
|
_frameBuffer.removeWhere((seq, frame) => seq < currentSeq - 200); // 调整阈值
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
void clear() {
|
|
_frameBuffer.clear();
|
|
}
|
|
}
|