From 43eeef237fc76cd95212219694739f89c85d4958 Mon Sep 17 00:00:00 2001 From: liyi Date: Mon, 24 Feb 2025 17:03:31 +0800 Subject: [PATCH] =?UTF-8?q?fix=EF=BC=9A=E4=BC=98=E5=8C=96h264=E7=BB=84?= =?UTF-8?q?=E8=A3=85=E5=B8=A7=E6=96=B9=E6=B3=95=EF=BC=8C=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- assets/html/h264.html | 2 +- .../lockDetail/lockDetail_state.dart | 3 +- .../handle/impl/udp_talk_data_handler.dart | 2 + .../handle/other/h264_frame_handler.dart | 73 ++++++++++++------- 4 files changed, 52 insertions(+), 28 deletions(-) diff --git a/assets/html/h264.html b/assets/html/h264.html index 97143565..63303e3c 100644 --- a/assets/html/h264.html +++ b/assets/html/h264.html @@ -56,7 +56,7 @@ }, flushingTime: 0, // 禁用自动刷新 clearBuffer: false, // 保留解码缓存 - maxBufferLength: 2, + fps:20, onReady: () => { console.log('播放器初始化完成'); // 通知Flutter端准备就绪 diff --git a/lib/main/lockDetail/lockDetail/lockDetail_state.dart b/lib/main/lockDetail/lockDetail/lockDetail_state.dart index 5e168524..760f1289 100755 --- a/lib/main/lockDetail/lockDetail/lockDetail_state.dart +++ b/lib/main/lockDetail/lockDetail/lockDetail_state.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; +import 'package:star_lock/main/lockDetail/lockSet/lockSet/lockSetInfo_entity.dart'; import '../../../blue/io_reply.dart'; import '../../lockMian/entity/lockListInfo_entity.dart'; @@ -9,7 +10,7 @@ import '../../lockMian/entity/lockListInfo_entity.dart'; class LockDetailState { Rx keyInfos = LockListInfoItemEntity().obs; - + final Rx lockSetInfoData = LockSetInfoData().obs; late StreamSubscription replySubscription; StreamSubscription? lockSetOpenOrCloseCheckInRefreshLockDetailWithAttendanceEvent; StreamSubscription? LockSetChangeSetRefreshLockDetailWithTypeSubscription; diff --git a/lib/talk/starChart/handle/impl/udp_talk_data_handler.dart b/lib/talk/starChart/handle/impl/udp_talk_data_handler.dart index a95b1c78..cb00a0d3 100644 --- a/lib/talk/starChart/handle/impl/udp_talk_data_handler.dart +++ b/lib/talk/starChart/handle/impl/udp_talk_data_handler.dart @@ -160,6 +160,8 @@ class UdpTalkDataHandler extends ScpMessageBaseHandle final TalkDataH264Frame talkDataH264Frame = TalkDataH264Frame(); talkDataH264Frame.mergeFromBuffer(talkData.content); frameHandler.handleFrame(talkDataH264Frame); + AppLog.log( + "帧:${talkDataH264Frame.frameType},帧序号:${talkDataH264Frame.frameSeq},对应I帧序号:${talkDataH264Frame.frameSeqI}"); } /// 处理图片数据 diff --git a/lib/talk/starChart/handle/other/h264_frame_handler.dart b/lib/talk/starChart/handle/other/h264_frame_handler.dart index 5eaa27df..2b4ea1ee 100644 --- a/lib/talk/starChart/handle/other/h264_frame_handler.dart +++ b/lib/talk/starChart/handle/other/h264_frame_handler.dart @@ -1,52 +1,51 @@ +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 Map _frameBuffer = {}; + final LinkedHashMap _frameBuffer = LinkedHashMap(); final void Function(List frameData) onCompleteFrame; - int _lastProcessedSeq = -1; + + final LinkedHashMap _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 sortedSeqs = _frameBuffer.keys.toList()..sort(); final List framesToProcess = []; + int? startFrameSeq; // 从当前帧开始向前找到最近的 I 帧或 P 帧 - int? startFrameSeq; - for (var seq in sortedSeqs.reversed) { - final frame = _frameBuffer[seq]; - if (frame?.frameType == TalkDataH264Frame_FrameTypeE.I) { + 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 (frame?.frameType == TalkDataH264Frame_FrameTypeE.P) { - // 检查 P 帧是否有对应的 I 帧 - if (_frameBuffer.containsKey(frame?.frameSeqI)) { + } else if (frameType == TalkDataH264Frame_FrameTypeE.P) { + if (_frameBuffer.containsKey(_frameBuffer[seq]!.frameSeqI)) { startFrameSeq = seq; break; } else { - // 丢弃没有对应 I 帧的 P 帧 _frameBuffer.remove(seq); + _frameTypeIndex.remove(seq); } } } if (startFrameSeq != null) { - // 收集从 I 帧或 P 帧开始的连续帧 - int expectedSeq = startFrameSeq; - for (var seq in sortedSeqs.where((s) => s >= startFrameSeq!)) { - if (seq != expectedSeq) break; + for (int seq = startFrameSeq; _frameBuffer.containsKey(seq); seq++) { framesToProcess.add(seq); - expectedSeq++; } if (framesToProcess.isNotEmpty) { @@ -57,28 +56,50 @@ class H264FrameHandler { } } - void _clearOldFrames(int currentSeq) { - // 清理比当前帧序列旧的帧 - _frameBuffer.removeWhere((seq, frame) => seq < currentSeq - 200); // 调整阈值 - } - void _processFrames(List frameSeqs) { // 按顺序组装帧数据 - final List assembledData = []; + // final List 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.addAll(frame.frameData); + 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); + } }