1.查看操作记录按门铃带图片问题
2.视频对讲优化
This commit is contained in:
parent
dfb368d822
commit
d3969b6ba5
@ -142,7 +142,6 @@ class ConfiguringWifiLogic extends BaseGetXController {
|
|||||||
String result = utf8String(secretKeyList);
|
String result = utf8String(secretKeyList);
|
||||||
|
|
||||||
AppLog.log('解析配网信息: $result');
|
AppLog.log('解析配网信息: $result');
|
||||||
AppLog.log('使用传入的RSSI值: ${state.rssi.value}');
|
|
||||||
|
|
||||||
// 解析 JSON 字符串为 Map
|
// 解析 JSON 字符串为 Map
|
||||||
Map<String, dynamic> jsonMap = json.decode(result);
|
Map<String, dynamic> jsonMap = json.decode(result);
|
||||||
|
|||||||
@ -318,7 +318,7 @@ class _MessageListPageState extends State<MessageListPage>
|
|||||||
Container(
|
Container(
|
||||||
width: 0.5,
|
width: 0.5,
|
||||||
height: 120.h,
|
height: 120.h,
|
||||||
color: AppColors.placeholderTextColor,
|
color: Color.fromRGBO(0, 0, 0, 0.2),
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
)),
|
)),
|
||||||
@ -352,12 +352,13 @@ class _MessageListPageState extends State<MessageListPage>
|
|||||||
),
|
),
|
||||||
child: Container(
|
child: Container(
|
||||||
width: 1.sw,
|
width: 1.sw,
|
||||||
margin: EdgeInsets.only(left: 20.w, right: 20.w, top: 8.h),
|
margin: EdgeInsets.only(left: 20.w, right: 20.w, top: 20.h, bottom: 20.h),
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
Wrap(
|
Wrap(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
|
// 时间
|
||||||
Container(
|
Container(
|
||||||
margin: EdgeInsets.only(top: 4.h),
|
margin: EdgeInsets.only(top: 4.h),
|
||||||
child: Text(
|
child: Text(
|
||||||
@ -370,6 +371,7 @@ class _MessageListPageState extends State<MessageListPage>
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
// 竖线
|
||||||
Container(
|
Container(
|
||||||
width: 1,
|
width: 1,
|
||||||
height: 10,
|
height: 10,
|
||||||
@ -378,8 +380,10 @@ class _MessageListPageState extends State<MessageListPage>
|
|||||||
? AppColors.blackColor
|
? AppColors.blackColor
|
||||||
: AppColors.placeholderTextColor,
|
: AppColors.placeholderTextColor,
|
||||||
),
|
),
|
||||||
Container(transform: Matrix4.translationValues(0, -22, 0),
|
// 标题
|
||||||
child: Text(' ${messageItemEntity.data!}',
|
Container(
|
||||||
|
margin: EdgeInsets.only(top: 2.h),
|
||||||
|
child: Text('${messageItemEntity.data!}',
|
||||||
maxLines: 2,
|
maxLines: 2,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
@ -389,7 +393,7 @@ class _MessageListPageState extends State<MessageListPage>
|
|||||||
: AppColors.placeholderTextColor,
|
: AppColors.placeholderTextColor,
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
Container(transform: Matrix4.translationValues(0, -8, 0), child: GestureDetector(
|
Container(margin: EdgeInsets.only(top: 10.h), child: GestureDetector(
|
||||||
child: Text('点击查看', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20.sp, color: AppColors.mainColor),),
|
child: Text('点击查看', style: TextStyle(fontWeight: FontWeight.w500, fontSize: 20.sp, color: AppColors.mainColor),),
|
||||||
),alignment: Alignment.centerRight,)
|
),alignment: Alignment.centerRight,)
|
||||||
],
|
],
|
||||||
|
|||||||
@ -44,29 +44,6 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
// 添加成员变量缓存帧索引
|
// 添加成员变量缓存帧索引
|
||||||
final Map<TalkDataH264Frame_FrameTypeE, List<MapEntry<int, int>>> _frameIndexCache = {};
|
final Map<TalkDataH264Frame_FrameTypeE, List<MapEntry<int, int>>> _frameIndexCache = {};
|
||||||
bool _frameIndexDirty = true;
|
bool _frameIndexDirty = true;
|
||||||
// 更新帧缓冲区时标记索引为脏数据
|
|
||||||
void _invalidateFrameIndex() {
|
|
||||||
_frameIndexDirty = true;
|
|
||||||
}
|
|
||||||
// 构建帧索引
|
|
||||||
List<MapEntry<int, int>> _buildFrameIndex(TalkDataH264Frame_FrameTypeE frameType) {
|
|
||||||
if (!_frameIndexDirty && _frameIndexCache.containsKey(frameType)) {
|
|
||||||
return _frameIndexCache[frameType]!;
|
|
||||||
}
|
|
||||||
|
|
||||||
final List<MapEntry<int, int>> index = [];
|
|
||||||
for (int i = 0; i < state.h264FrameBuffer.length; i++) {
|
|
||||||
final frame = state.h264FrameBuffer[i];
|
|
||||||
if (frame['frameType'] == frameType) {
|
|
||||||
index.add(MapEntry(frame['frameSeq'] as int, i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
index.sort((a, b) => a.key.compareTo(b.key));
|
|
||||||
|
|
||||||
_frameIndexCache[frameType] = index;
|
|
||||||
_frameIndexDirty = false;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加网络质量评估变量
|
// 添加网络质量评估变量
|
||||||
int _networkQualityScore = 5; // 1-5分,5为最佳
|
int _networkQualityScore = 5; // 1-5分,5为最佳
|
||||||
@ -532,6 +509,30 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新帧缓冲区时标记索引为脏数据
|
||||||
|
void _invalidateFrameIndex() {
|
||||||
|
_frameIndexDirty = true;
|
||||||
|
}
|
||||||
|
// 构建帧索引
|
||||||
|
List<MapEntry<int, int>> _buildFrameIndex(TalkDataH264Frame_FrameTypeE frameType) {
|
||||||
|
if (!_frameIndexDirty && _frameIndexCache.containsKey(frameType)) {
|
||||||
|
return _frameIndexCache[frameType]!;
|
||||||
|
}
|
||||||
|
|
||||||
|
final List<MapEntry<int, int>> index = [];
|
||||||
|
for (int i = 0; i < state.h264FrameBuffer.length; i++) {
|
||||||
|
final frame = state.h264FrameBuffer[i];
|
||||||
|
if (frame['frameType'] == frameType) {
|
||||||
|
index.add(MapEntry(frame['frameSeq'] as int, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index.sort((a, b) => a.key.compareTo(b.key));
|
||||||
|
|
||||||
|
_frameIndexCache[frameType] = index;
|
||||||
|
_frameIndexDirty = false;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
int _findEarliestIFrame() {
|
int _findEarliestIFrame() {
|
||||||
final iFrameIndexes = _buildFrameIndex(TalkDataH264Frame_FrameTypeE.I);
|
final iFrameIndexes = _buildFrameIndex(TalkDataH264Frame_FrameTypeE.I);
|
||||||
return iFrameIndexes.isNotEmpty ? iFrameIndexes.first.value : -1;
|
return iFrameIndexes.isNotEmpty ? iFrameIndexes.first.value : -1;
|
||||||
@ -1344,7 +1345,7 @@ class TalkViewNativeDecodeLogic extends BaseGetXController {
|
|||||||
try {
|
try {
|
||||||
// 使用较短超时时间
|
// 使用较短超时时间
|
||||||
final textureId = await VideoDecodePlugin.initDecoder(config)
|
final textureId = await VideoDecodePlugin.initDecoder(config)
|
||||||
.timeout(Duration(milliseconds: 800));
|
.timeout(Duration(milliseconds: 500));
|
||||||
|
|
||||||
if (textureId != null) {
|
if (textureId != null) {
|
||||||
state.textureId.value = textureId;
|
state.textureId.value = textureId;
|
||||||
|
|||||||
@ -41,7 +41,7 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
|
|
||||||
final LockDetailState lockDetailState = Get.put(LockDetailLogic()).state;
|
final LockDetailState lockDetailState = Get.put(LockDetailLogic()).state;
|
||||||
|
|
||||||
int bufferSize = 8; // 增大缓冲区,满时才渲染
|
int bufferSize = 3; // 增大缓冲区,满时才渲染
|
||||||
|
|
||||||
int audioBufferSize = 2; // 音频默认缓冲2帧
|
int audioBufferSize = 2; // 音频默认缓冲2帧
|
||||||
bool _isFirstAudioFrame = true; // 是否是第一帧
|
bool _isFirstAudioFrame = true; // 是否是第一帧
|
||||||
@ -123,11 +123,12 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
_playAudioFrames();
|
_playAudioFrames();
|
||||||
break;
|
break;
|
||||||
case TalkData_ContentTypeE.Image:
|
case TalkData_ContentTypeE.Image:
|
||||||
|
// 如果缓冲区已满,移除最旧的帧
|
||||||
|
if (state.videoBuffer.length >= bufferSize) {
|
||||||
|
state.videoBuffer.removeAt(0);
|
||||||
|
}
|
||||||
// 固定长度缓冲区,最多保留bufferSize帧
|
// 固定长度缓冲区,最多保留bufferSize帧
|
||||||
state.videoBuffer.add(talkData);
|
state.videoBuffer.add(talkData);
|
||||||
if (state.videoBuffer.length > bufferSize) {
|
|
||||||
state.videoBuffer.removeAt(0); // 移除最旧帧
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -370,12 +371,21 @@ class TalkViewLogic extends BaseGetXController {
|
|||||||
|
|
||||||
requestPermissions();
|
requestPermissions();
|
||||||
|
|
||||||
|
bool _isValidImageData(List<int> data) {
|
||||||
|
// 检查数据长度
|
||||||
|
if (data.length < 10) return false;
|
||||||
|
// 检查JPEG格式 (0xFFD8FF)
|
||||||
|
if (data[0] == 0xFF && data[1] == 0xD8 && data[2] == 0xFF) return true;
|
||||||
|
// 检查PNG格式 (0x89504E47)
|
||||||
|
if (data[0] == 0x89 && data[1] == 0x50 && data[2] == 0x4E && data[3] == 0x47) return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// 启动视频渲染定时器(10fps)
|
// 启动视频渲染定时器(10fps)
|
||||||
videoRenderTimer = Timer.periodic(const Duration(milliseconds: 100), (_) {
|
videoRenderTimer = Timer.periodic(const Duration(milliseconds: 100), (_) {
|
||||||
final int now = DateTime.now().millisecondsSinceEpoch;
|
final int now = DateTime.now().millisecondsSinceEpoch;
|
||||||
if (state.videoBuffer.isNotEmpty) {
|
if (state.videoBuffer.isNotEmpty) {
|
||||||
final TalkData oldestFrame = state.videoBuffer.removeAt(0);
|
final TalkData oldestFrame = state.videoBuffer.removeAt(0);
|
||||||
if (oldestFrame.content.isNotEmpty) {
|
if (oldestFrame.content.isNotEmpty && _isValidImageData(oldestFrame.content)) {
|
||||||
state.listData.value =
|
state.listData.value =
|
||||||
Uint8List.fromList(oldestFrame.content); // 备份原始数据
|
Uint8List.fromList(oldestFrame.content); // 备份原始数据
|
||||||
final int decodeStart = DateTime.now().millisecondsSinceEpoch;
|
final int decodeStart = DateTime.now().millisecondsSinceEpoch;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user