diff --git a/lib/main/lockDetail/lockDetail/lockDetail_logic.dart b/lib/main/lockDetail/lockDetail/lockDetail_logic.dart index cb1f7093..5d8bf397 100755 --- a/lib/main/lockDetail/lockDetail/lockDetail_logic.dart +++ b/lib/main/lockDetail/lockDetail/lockDetail_logic.dart @@ -726,9 +726,13 @@ class LockDetailLogic extends BaseGetXController { // 判断是否为WiFi锁 final network = currentKeyInfo.network; if (network != null && (network.peerId != null && network.peerId!.isNotEmpty)){ + showToast('wifi锁进行蓝牙透传开锁'.tr); // 发送蓝牙透传开锁指令 await _sendUnlockViaBluetooth(); - } else { + } + // 判断是否为网关锁 + if (state.keyInfos.value.hasGateway == 1) { + showToast('网关锁进行远程开锁api开锁'.tr); // 发送远程开锁API final LoginEntity entity = await ApiRepository.to.remoteOpenLock(lockId: lockId.toString(), timeOut: 60); if (entity.errorCode!.codeIsSuccessful) { diff --git a/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart b/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart index 4ebd929a..32a52790 100644 --- a/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart +++ b/lib/talk/starChart/views/native/talk_view_native_decode_logic.dart @@ -398,8 +398,6 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { } else if (bufferLength > 40) { // 其他平台原有逻辑 _dropOldPFrame(); - } else if (bufferLength > 30) { - _dropSomeBFrame(); } } void _dropOldFramesAggressively() { @@ -423,50 +421,63 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { _invalidateFrameIndex(); } } - - void _dropSomeBFrame() { - // 如果存在B帧,丢弃部分旧的B帧 - final bFrameIndex = state.h264FrameBuffer.indexWhere((frame) => - frame['frameType'] == TalkDataH264Frame_FrameTypeE.I && - frame['frameSeq'] < (_lastFrameSeq ?? 0) - 30); - - if (bFrameIndex != -1) { - state.h264FrameBuffer.removeAt(bFrameIndex); + + /// 仅保留关键帧(I帧和最近的P帧)以减少处理负载 + void _keepOnlyKeyFrames() { + final List> keyFrames = []; + int lastPFrameIndex = -1; + + // 从后向前遍历,优先保留最新的帧 + for (int i = state.h264FrameBuffer.length - 1; i >= 0; i--) { + final frame = state.h264FrameBuffer[i]; + final frameType = frame['frameType']; + + if (frameType == TalkDataH264Frame_FrameTypeE.I) { + keyFrames.add(frame); + break; // 找到最新的I帧后停止 + } else if (frameType == TalkDataH264Frame_FrameTypeE.P && lastPFrameIndex == -1) { + keyFrames.add(frame); + lastPFrameIndex = i; + } + } + + if (keyFrames.isNotEmpty) { + // 只保留关键帧,反转顺序使其按时间顺序排列 + state.h264FrameBuffer.clear(); + state.h264FrameBuffer.addAll(keyFrames.reversed); _invalidateFrameIndex(); } } - /// 启动帧处理定时器 + /// 启动帧处理定时器 - 优化版:动态帧率调整 void _startFrameProcessTimer() { // 取消已有定时器 _stopFrameProcessTimer(); - // 计算定时器间隔,确保以目标帧率处理帧 - // iOS平台使用更精确的定时器间隔 - final int intervalMs = Platform.isIOS + // 初始间隔设置 + int baseIntervalMs = Platform.isIOS ? max(16, min(33, (1000 / state.targetFps).round())) // iOS使用更严格的范围 : max(16, min(40, (1000 / state.targetFps).round())); // 创建新定时器 - state.frameProcessTimer = Timer.periodic(Duration(milliseconds: intervalMs), (timer) { + state.frameProcessTimer = Timer.periodic(Duration(milliseconds: baseIntervalMs), (timer) { _processNextFrameFromBuffer(); }); - AppLog.log('启动帧处理定时器,目标帧率: ${state.targetFps}fps,间隔: ${intervalMs}ms'); + AppLog.log('启动帧处理定时器,目标帧率: ${state.targetFps}fps,初始间隔: ${baseIntervalMs}ms'); } /// 添加:快速清理缓冲区方法 void _clearFrameBufferQuickly() { - // 只保留最新的少量帧,加快切换响应 - if (state.h264FrameBuffer.length > 3) { - // 保留最新的3帧 - state.h264FrameBuffer.removeRange(0, state.h264FrameBuffer.length - 3); - } + // 完全清空帧缓冲区,避免旧帧影响新流 + state.h264FrameBuffer.clear(); // 重置帧序列状态 _lastFrameSeq = null; lastDecodedIFrameSeq = null; _decodedIFrames.clear(); state.isProcessingFrame = false; + _frameIndexDirty = true; + _frameIndexCache.clear(); } /// 停止帧处理定时器 @@ -575,8 +586,8 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { return state.h264FrameBuffer.isNotEmpty ? 0 : -1; } - /// 从缓冲区处理下一帧 - void _processNextFrameFromBuffer() async { + /// 从缓冲区处理下一帧 - 优化版:简化逻辑和动态调整 + Future _processNextFrameFromBuffer() async { final stopwatch = Stopwatch()..start(); _monitorFrameProcessingPerformance(); final startTime = DateTime.now().microsecondsSinceEpoch; @@ -600,12 +611,23 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { try { state.isProcessingFrame = true; - // 添加智能丢帧策略 - _implementSmartFrameDropping(); + // 智能丢帧策略:根据缓冲区大小动态调整 + final bufferLength = state.h264FrameBuffer.length; + if (bufferLength > 50) { + // 缓冲区溢出,保留最新20帧 + final newBuffer = state.h264FrameBuffer.sublist(max(0, bufferLength - 20)); + state.h264FrameBuffer.clear(); + state.h264FrameBuffer.addAll(newBuffer); + _invalidateFrameIndex(); + } else if (bufferLength > 30 && Platform.isAndroid) { + // Android平台缓冲区较大时,只处理I帧和关键P帧 + _keepOnlyKeyFrames(); + } else { + // 正常智能丢帧 + _implementSmartFrameDropping(); + } // 动态调整处理策略基于缓冲区长度 - final bufferLength = state.h264FrameBuffer.length; - // 更智能的帧率调整策略 // iOS平台优化:更积极的缓冲区管理 if (Platform.isIOS) { @@ -1306,7 +1328,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { AppLog.log(error.message!); } - // 切换清晰度的方法,后续补充具体实现 + // 切换清晰度的方法,优化切换速度 void onQualityChanged(String quality) async { state.currentQuality.value = quality; TalkExpectReq talkExpectReq = StartChartManage().getDefaultTalkExpect(); @@ -1335,8 +1357,27 @@ class TalkViewNativeDecodeLogic extends BaseGetXController { /// 修改发送预期数据 StartChartManage().changeTalkExpectDataTypeAndReStartTalkExpectMessageTimer(talkExpect: talkExpectReq); - // 不立即loading,继续解码旧流帧,等待frameSeq回绕检测 - // 仅重置frameSeq回绕检测标志 + // 立即切换清晰度:清理旧帧缓冲区并重新初始化解码器 + // 1. 停止当前帧处理 + _stopFrameProcessTimer(); + + // 2. 立即清理旧的帧缓冲区 + _clearFrameBufferQuickly(); + + // 3. 更新视频分辨率设置 + StartChartManage().videoWidth = width; + StartChartManage().videoHeight = height; + + // 4. 立即重新初始化解码器 + await _resetDecoderForNewStream(width, height); + + // 5. 启动帧处理 + _startFrameProcessTimer(); + + // 6. 显示加载动画 + Future.microtask(() => state.isLoading.value = true); + + // 7. 重置帧序列相关状态 _pendingStreamReset = false; _pendingResetWidth = width; _pendingResetHeight = height;